!--------------------------------------------------------------
! [03/06/04] I think that routine
!	CheckAuxiliaryIsInConstraint
! should be moved to Tom's code MPSGE.F90 and called there
!  in some appropriate spot
!--------------------------------------------------------------

!--------------------------------------------------------------
! [08/06/04] Tom's "new" rule about d: lines is that every $demand:
!  block is allowed to have at most one d: line.
!--------------------------------------------------------------

!--------------------------------------------------------------
! [08/06/04] How to calculate supply and demand for a commodity, taken
!  from Tom's email to me dated 07/06/04.
! 1. Market supply for good p(i) =
! 
!         sum of netputs associated with o:p(i) records
! 
!         + sum of positive exogenous endowments,
!                 e:p(i) q:e0(i) records where e0(i) > 0
! 
!         + sum of positive endogenous endowments,
!                 e:p(i) q:e0(i) r:t  records where t*e0(i) > 0
! 
! 2. Market demand for good p(i) =
! 
!         sum of demands associated with i:p(i) records
! 
!         + sum of final demands, d:p(i) which would be of
!                 the form RA(h)/p(i)
! 
!         + sum of negative exogenous endowmetns,
!                 e:p(i) q:e0(i) records where e0(i) < 0
! 
!         + sum of negative endogenous endowments,
!                 e:p(i) q:e0(i) r:t  records where t*e0(i) < 0
! 
! The verbal logic here is quite simple.  All commodities are supplied
! to the market either as an initial endowment or as a produced good (or
! as both an initial endowment and a produced good).  All commodities
! taken from the market either as an exogenous "negative endowment" or
! as a production input or as a good demanded by households.
! 
! On the supply side there are two contributions to the market total:
! producer netputs and initial endowments.  On the demand side there are
! three contributions to the market total: producer net demands, initial
! "endowments" and final demands.
!--------------------------------------------------------------


!--------------------------------------------------------------
! [18/04/04] Important information provided by Tom.
! This relates to what he calls the "new" syntax rules for MPSGE. [Perhaps this
!   will be called "version 2, April 2004" of MPSGE syntax.
! 1. Can only be one $prod:y block for any sector y.
! (a) In the current implementation of MGE2XX, do not allow $ in declaration blocks.
!    So, if see y(s) in declaration block and $prod:y(o), can infer that O=S.
! (b) When, later, MGE2XX allows $ in declaration blocks, if see 
!      y(s)$y0(s) in the declaration block and see $prod:y(o), can infer that
!      O = (s1, s: y0(s1) <> 0)
! 2. What is written above for $sectors and $prod: blocks also applies
!    to $consumers and $demand blocks.
!--------------------------------------------------------------


!--------------------------------------------------------------
! Rules for p: fields in o: or i: lines
! At most one p: field in any o: or i: line.
! If it is missing, value is 1.
! Value in p: field is total (across all taxes on this line) power of taxes.
! Eg. i:p1   p:x  a:gov t:y.   Then x=(1+y)*P1 (at benchmark if in equilibruim)
! Eg. o:p1   p:x  a:gov t:y.   Then x=(1-y)*P1 (at benchmark if in equilibruim)
! Eg. i:p1   p:x  a:gov t:y  a:ra t:z.   Then x=(1+y+z)*P1 (at benchmark if in equilibruim)
! Eg. o:p1   p:x  a:gov t:y  a:ra t:z.   Then x=(1-y-z)*P1 (at benchmark if in equilibruim)
!--------------------------------------------------------------


!--------------------------------------------------------------
! Expressions are allowed in q:, t: p: and m: fields
! [n: field must contain name of an auxiliary variable]
! ** Ken'scode here must be modified to handle expressions in t: and p: fields - and later in m: fields **
!--------------------------------------------------------------


  




! Questions for Laurent
! 1. IOQFieldValueVar. Try to explain why need this when are taxes on outputs 
!      but not when are taxes on inputs.
!   This must be documented. I think that
!    (a) in o: field, the q: field coeff is a pre-sim value INCLUDING taxes but
!    (b) in i: field, the q: field coeff is a pre-sim value NOT INCLUDING taxes.
!    Check this with Laurent. Put some of this into the labelinfo.
! 2. Need to test this with 2 taxes on i: line. In particular need to 
!     test mixedTAB output in that case.
! 3. Need an example with just one tax on o: line. This is needed to test correct
!     use of IOQFieldValueVar in that case.
! 4. $demand
!   (a) Always exactly one d: field? [Check with Laurent]
!   (b) What happens if are arguments involved in d: fields?
! 5. Tax revenue. Can a: field in i: or o: field have arguments? I assume so. example??
!     In adding revenue from a: terms, I have assumed no arguments. Will probably
!      need to change this.
! Documentation.
! 1. Rule for read header:
! This is done in subroutine GetReadHeader(NameToRead, NewHeader)
!   (a) if length <= 4, try to use it
!   (b) otherwise omit vowels from right-hand end (though not the first letter if it is a vowel)
!        to get a candidate. Stop omitting vowels if length gets to 4.
!   (c) Truncate candidate from (a) or (b) to length 4.
!   (d) Use this is not already used.
!   (e) Otherwise ?? (nothing implemented yet)
! 2. Check all calls to ErrorStop for user errors
! 3. Check all calls to GiveWarning for user advice  

!

module mpsGP

! module used in conversion to GEMPACK TAB and Command files

	use mpsge

! Whether to translate to a mixed or a linear TAB file
!  Only one of these will be true
	logical :: MixedTABFile, LinearTABFile
! if EchoMainProgressGP is true, indicate current block through the main routines
!  used to convert to GEMPACK, namely, routines SetupGEMPACKNames, ConvertToGP, DoMarketClearingEquations
	logical :: EchoMainProgressGP=.true.

! Lengths
	integer, parameter :: llst=12  ! Max length of set name
	integer, parameter :: llcs=12  ! Max length of Coefficient name
	integer, parameter :: llvc=15  ! Max length of (linear) Variable name
	integer, parameter :: llrc=15  ! Max length of real constant
	integer, parameter :: llindex=12  ! Max length of index
	
! Declarations/Types added by KP

	integer :: NumSets  !! Number of sets in the MPS file

	type SetGP
	  character (len=llst) :: name
	  type(SetGP), pointer :: next  !! pointer to the next setGP in the list
	end type SetGP

	type(setGP), pointer :: SetGPList !! List of all the SetGPs
	type(setGP), pointer :: SetGPLast !! Last of all the SetGPs

! For subset mappings
	logical, dimension(:,:), allocatable :: IsSubsetGP  !! Tells if each set is a subset of any other set

	type GPCoeffVarReal    ! GEMPACK Coefficient or Variable or Real
	  character :: type  ! 'c' for coefficient or 'v' for variable or 'r' for real
! [07/04/04] Add "+5" so can tell if name is too long when process it as a GPCoeffVarReal.
	  character (len=MAX(llcs,llvc,llrc)+5) :: name    ! Coeff/Var name or Real as string
	  type (domain), pointer :: arg      ! Sets over which arguments range
	  character (len=80) :: labelinfo  ! labelling information (between #)
! Next two only apply to a variable
	  character :: VarType  ! 'p' for %-change, 'c' for change
	  character (len=12) :: OrigLevel  ! Coeff or Real which is the ORIG_LEVEL ! ignore if OrigLevel is ' '
! Next only applies to a coefficient
	  logical :: IsParam  ! Tells if this coefficient is a parameter
! Next applies only to coefficients and levels variables
	  logical :: IsGE0 ! Tells if this must be non-negative
	end type GPCoeffVarReal

        integer, parameter :: iotabgp=21   !! Unit number of the output GEMPACK TAB file
        integer, parameter :: iocmfgp=22   !! Unit number of the output GEMPACK Command file
        integer, parameter :: iohargp=23   !! Unit number of the input Header Array file
        integer, parameter :: iotabstigp=23   !! Unit number of the output TABLO STI file
        character (len=255) :: tabfilename, cmffilename, tabfileroot, harfilename, tabstifilename

	logical :: UseHarFileInfo

	integer, parameter :: llhd=4   !! Length of a header in GEMPACK
	type HeaderGP  ! List of headers
	  character (len=llhd) :: header
	  type (HeaderGP), pointer :: next  !! Pointer to the next one in the list
	end type HeaderGP

	type (HeaderGP), pointer :: ReadHeaderGPList !! List of headers used for reading
	type (HeaderGP), pointer :: ReadHeaderGPLast !! Last header in list of headers used for reading

	integer LengthGPDeclarationName
	parameter (LengthGPDeclarationName = 20)
	type GPDeclaration   ! List of various types of GEMPACK declarations
	  character (len=2) :: type  !! 'cs' for Coeff, 'vc' for Variable, 'eq' for equation
	  character (len=LengthGPDeclarationName) :: name  !! Coeff/Var/Equation name
	  type (GPDeclaration), pointer :: next !! Pointer to the next declaration in this list
	end type GPDeclaration

	type (GPDeclaration), pointer :: GPDeclarationList !! Pointer to first in GPDeclarationList 
	type (GPDeclaration), pointer :: GPDeclarationLast !! Pointer to last in GPDeclarationList

	type GPName   ! List of various types of GEMPACK declarations
	  character (len=LengthGPDeclarationName) :: name  !! Coeff/Var/Equation name
	  character :: UserSystemType !! 'u' for names supplied by user, 's' for names made up by our system
	  type (domain), pointer :: arg      ! Sets over which arguments range
! next only for variables
	  character :: type ! 'v' for variable, 'c' for coefficient
	  character :: ExogEndogStatus ! 'n' for endogenous, 'x' for exogenous, '?' for not sure
	  type (GPName), pointer :: next !! Pointer to the next name in this list
	end type GPName

	type (GPName), pointer :: GPNameList !! Pointer to first in GPNameList 
	type (GPName), pointer :: GPNameLast !! Pointer to last in GPNameList

	type GPRead   ! List of names of Coefficients whose values have been read
	  character (len=LengthGPDeclarationName) :: name  !! Coeff name
! ??	  type (domain), pointer :: arg      ! Sets over which arguments range
	  type (GPRead), pointer :: next !! Pointer to the next name in this list
	end type GPRead

	type (GPRead), pointer :: GPReadList !! Pointer to first in GPReadList 
	type (GPRead), pointer :: GPReadLast !! Pointer to last in GPReadList
	integer :: NumGPReads  !! Instant count of number of Read statements

	type GPCoeffMPSGE  !! List of Coeff appearing alone (not in expression) in MGE file
	  character (len=80) :: Name
!NO (just Name)	  type (symbol), pointer :: Symbol
	  type (domain), pointer :: MaxArg
	  integer :: NumTimesFound ! number of times this coeff is found in this  way
	  type (GPCoeffMPSGE), pointer :: next  ! Pointer to next in the list
	end type GPCoeffMPSGE

	type (GPCoeffMPSGE), pointer :: GPCoeffMPSGEList ! Pointer to first in list of all GPCoeffMPSGE
	type (GPCoeffMPSGE), pointer :: GPCoeffMPSGELast ! Pointer to last in list of all GPCoeffMPSGE

! When convert to GEMPACK, do two passes when writing TAB file
! On the first pass, just declare and read values of GEMPACK coefficient with
!  names taken directly from the MGE file. Set GPCoeffMPSGEPass true on this pass.
! On the second pass, declare all other coefficients and do the rest of the
!  TAB file - that is, all the formulas, equations, assertions etc. Set
!  GPCoeffMPSGEPass false on this pass.
! To do this, loop over BigCoeffPass=1,2. Set GPCoeffMPSGEPass true/false when BigCoeffPass=1/2 respectively.
	integer :: BigCoeffPass
	logical :: GPCoeffMPSGEPass
 

	type (GPCoeffVarReal) :: WalrasSlackVar !! Variable determined by difference between 2 sides 
					!! of omitted (Walras) equation. Should be zero.
! Sometimes WalrasSlack is a levels variable. [See routine DoMarketClearingEquations.] Then also use WalrasSlackCoeff
	type (GPCoeffVarReal) :: WalrasSlackCoeff 

	character (len=80) :: WalrasNumeraireString  !! expression for omitted market - eg pw or pm("s1")

        type functionGP
! Additions to Tom Rutherford's type function. These additions needed for GEMPACK
! This is actually a list of functionGP's
	  type (function), pointer :: functionMPSGE  !! Pointer to the MPSGE information

	  logical :: IsProdFunctionGP, IsDemandFunctionGP

!  The first lot below only apply for a $prod function
	  type (GPCoeffVarReal) :: ActivityLevelVar !! Variable after %prod:
	  logical :: SElastPresent, TElastPresent, SElastIsConstant, TElastIsConstant
	  type (field), pointer :: SElastField, TElastField
	  type (GPCoeffVarReal) :: SElasticity, TElasticity

! Next are for $prod functions
	  type (GPCoeffVarReal) :: TotalRevCoeff !! Total revenue as coefficient (relates to outputs)
	  type (GPCoeffVarReal) :: MargRevVar !! Marginal revenue as variable (relates to outputs)
	  type (GPCoeffVarReal) :: TotalCostCoeff !! Total cost as coefficient (relates to inputs)
	  type (GPCoeffVarReal) :: MargCostVar !! Marginal cost as variable (relates to inputs)
	  integer :: NumIFields, NumOFields  !! Number of i: and o: fields

	  type (netputGP), pointer :: FirstNetputGP   !! Points to first netputGP in netputGPList associated with this function 

! Next are for $demand functions
	  integer :: NumDFields, NumEFields  !! Number of d: and e: fields
	  type (GPCoeffVarReal) :: IncomeVar !! %-change in value of income for this agent
	  type (GPCoeffVarReal) :: TotalIncomeCoeff !! Total income for this consumer
		! Is equal to total value of endowments (summed over all e: lines) plus total tax income

	  type (endowmentGP), pointer :: FirstEndowmentGP   !! Points to first endowmentGP in endowmentGPList associated with this function 

          type (functionGP), pointer :: next      !! Pointer in linked list of all functionGPs
        end type functionGP

        type (functionGP), pointer :: FunctionGPList !! Pointer to the first functionGP in linked list
        type (functionGP), pointer :: FunctionGPLast !! Pointer to the last functionGP in linked list
	
        type netputGP
! Additions to Tom Rutherford's type netput. These additions needed for GEMPACK
! This is actually a list of netputGP's
	  type(netput), pointer :: netputMPSGE !! Pointer to the MPSGE netput

! The GEMPACK arguments for this netputGP may be different from netputMPSGE%arg. The
!  sets will be the same but they may be in the same order. For example,
! $prod:y(s)          t:etrn(s)
!  o:p(o)            q:supply(s,o)       p:0.8  a:gov  t:0.2     a:gov  t:t_p(o)
!  i:p(o)            q:interm(o,s)
!  i:pva(s)          q:totfac
! For netput beginning o:p(o), the netputMPSGE%arg are (s,o). Since the arguments in the q: field
!   are in the same order, IOArgGP will be the same (s,o).
! But for netput beginning i:p(o), the netputMPSGE%arg is (s,o). However, since the arguments in
!  the q: field are there sets but in a different order (ie, the q: field parameter has "full rank"),
!  IOArgGP will be (o,s) in that order.
! At present, IOArgGP and IOQFieldValueCoeff%arg are always the same. But use IOArgGP in the code
!  in case this changes in some special cases which are excluded at present.
	  type (domain), pointer :: IOArgGP  

!		IOPriceVar is the market price
	  type (GPCoeffVarReal) :: IOPriceVar    !! %-change in price (The price after o: or i: at start of line) 
	  type (GPCoeffVarReal) :: IOPriceCoeff    !! price (levels value) (The price after o: or i: at start of line) 
	  type (GPCoeffVarReal) :: IOQFieldQuantityCoeff  !! quantity (level) of each input or output (q: field)  
	  type (GPCoeffVarReal) :: IOQFieldQuantityVar  !! %-change in input or output quantity
	  type (GPCoeffVarReal) :: IOQFieldValueCoeff  !! value (level) of input or output
	  type (GPCoeffVarReal) :: IOQFieldValueVar    !! %-change in value of input or output
! Names given for this example
! $prod:y(s)          t:etrn(s)
!  o:p(o)            q:200
! IOPriceVar is p(o) and IOPriceCoeff is P_L(o)
! IOQFieldQuantityCoeff is QS_Y_P(s,o) and IOQFieldQuantityVar is p_qs_y_p(s,o)
! IOQFieldValueCoeff is VS_Y_P(s,o) and IOQFieldValueVar is p_vs_y_p(s,o)


! Next will be a real (eg q:200) or a Coefficient (eg q:totfac)
! Note that IOQFieldQuantityCoeffOrRealMPSGE is not set up if QFieldIsExpression is true
	  type (GPCoeffVarReal) :: IOQFieldQuantityCoeffOrRealMPSGE  !! MPSGE value (initial level) of input or output
! Now handle case where is an experssion in the q: field
	  logical :: QFieldIsExpression  !! Tells if QField is an expression
	  character (len=512) :: QFieldExpressionString   !! The expression in the q: field (if is such)
	  logical :: QFieldNeedGEMPACKCoeff  !! Tells if need a separate GEMPACK coefficient for the q: field 


! [26/04/04] Added to handle p: fields and expressions in p: fields
! Note that PFieldCoeffOrRealMPSGE is not set up if PFieldIsExpression is true
!NO??	  type (GPCoeffVarReal) :: PFieldCoeffOrRealMPSGE  !! MPSGE value of p: field
	  type (GPCoeffVarReal) :: PFieldCoeff  !! GEMPACK Coeff equal to p: field  
	  logical :: PFieldIsExpression  !! Tells if PField is an expression
	  character (len=512) :: PFieldExpressionString   !! The expression in the p: field (if is such)
!NO??	  logical :: PFieldNeedGEMPACKCoeff  !! Tells if need a separate GEMPACK coefficient for the p: field 

	  integer :: NumTaxTypes
! Next only needed if are one or more taxing agents
	  type (GPCoeffVarReal) :: IOPriceIncTaxesVar    !! %-change in price including taxes
! Next only needed for outputs when are one or more taxing agents. 
!		[Need this for update of the values in the output case. Need division in levels
!			equation for this value, so can't use product update. For inputs can use a product update.
!		        The difference relates to whether value includes taxes or not. Ken to check with Laurent to
!				try to express and explain this better.]

	  type (taxGP), pointer :: FirstTaxGP   !! Points to first taxGP in TaxGPList associated with this netput 

! Next only needed if are 2 or more tax types for this netput
	  type (GPCoeffVarReal) :: TotalTaxPowerCoeff  !! power of tax (all tax types)
	  type (GPCoeffVarReal) :: TotalTaxPowerVar  !! %-change in power of tax (all tax types)

	  type (netputGP), pointer :: next      !! Pointer in linked list of all netputGPs
        end type netputGP

        type (netputGP), pointer :: NetputGPList !! Pointer to the first netputGP in linked list
        type (netputGP), pointer :: NetputGPLast !! Pointer to the last netputGP in linked list

	type taxGP
! Additions to Tom Rutherford's type taxlist. These additions needed for GEMPACK
! This is actually a list of taxlistGP's
	  type(taxlist), pointer :: taxlistMPSGE !! Pointer to the MPSGE taxlist

! [28/04/04] HasMField tells if this has m: and n: fields rather than a t: field
! [09/06/04] Note that if there is an n: field, the m: field may not be present since
!  the default value is "m:1". So really HasMField should have been called HasNField. Introduce
!   HasNField also.
	  logical :: HasMField, HasNField

	  type (GPCoeffVarReal) :: TaxPowerCoeff  !! power of tax
	  type (GPCoeffVarReal) :: TaxRateCoeff  !! rate of tax (number like 0.13)
	  type (GPCoeffVarReal) :: TaxRevenueCoeff  !! tax revenue
	  type (GPCoeffVarReal) :: TaxPowerVar  !! %-change in power of tax
	  type (GPCoeffVarReal) :: TaxRateChangeVar  !! change in tax rate (number like 0.05)
	  type (GPCoeffVarReal) :: TaxRevenueChangeVar  !! change in tax revenue
! Next will be a real (eg t:0.2) or a Coefficient (eg t:t_p(o))
! [26/04/04] TaxRateCoeffOrRealMPSGE is not set up if TFieldIsExpression is true. Nor if HasMField or HasNField is true.
	  type (GPCoeffVarReal) :: TaxRateCoeffOrRealMPSGE  !! MPSGE value (initial level) of tax rate
! [26/04/04] Added to handle expressions in t: fields
	  logical :: TFieldIsExpression  !! Tells if TField is an expression
	  character (len=512) :: TFieldExpressionString   !! The expression in the t: field (if is such)
!NO?? - always true??	  logical :: TFieldNeedGEMPACKCoeff  !! Tells if need a separate GEMPACK coefficient for the t: field

!-------------------------------------------------------------------------------------
! [28/04/04] To handle m: and n: fields
! Next only set up if HasMField is true.
! MFieldCoeffOrRealMPSGE is not set up if MFieldIsExpression is true
	  type (GPCoeffVarReal) :: MFieldCoeffOrRealMPSGE  !! MPSGE value (initial level) of m: field
! Actual rate (at any stage) is NFieldCoeff*MFieldCoeff when HasMField is true
	  type (GPCoeffVarReal) :: MFieldCoeff  !! Levels variable, initialised at m: field value, can be shocked
	  type (GPCoeffVarReal) :: MFieldVar  !! Linear change variable, the change in MFieldCoeff

	  logical :: MFieldIsExpression  !! Tells if TField is an expression
	  character (len=512) :: MFieldExpressionString   !! The expression in the t: field (if is such)

! When is m: field, must also be an n: field (but can be n: field without explicit m: field since
!   m:1 is the default 
	  type (GPCoeffVarReal) :: NFieldCoeff  !! level of n: variable
	  type (GPCoeffVarReal) :: NFieldVar  !! change in level of n: variable
!-------------------------------------------------------------------------------------

	  type(taxGP), pointer :: next    !! Pointer to next in linked list of all taxGPs
	end type taxGP

        type (taxGP), pointer :: TaxGPList !! Pointer to the first taxGP in linked list
        type (taxGP), pointer :: TaxGPLast !! Pointer to the last taxGP in linked list

	type endowmentGP
! Additions to Tom Rutherford's type endowment. These additions needed for GEMPACK
! This is actually a list of endowmentGP's
	  type(endowment), pointer :: endowmentMPSGE !! Pointer to the MPSGE endowment

! EndowArgGP is analagous to IOArgGP
! At present, EndowArgGP and EndowQFieldValueCoeff%arg are always the same. But use EndowArgGP in the code
!  in case this changes in some special cases which are excluded at present.
	  type (domain), pointer :: EndowArgGP  

! The next 6 are analagous to the corresponding IO things in a netputGP
!			EndowPriceVar is the market price of this endowment
	  type (GPCoeffVarReal) :: EndowPriceVar    !! %-change in price (The price after e: at start of line)
	  type (GPCoeffVarReal) :: EndowPriceCoeff    !! price (levels value) (The price after e: at start of line)
	  type (GPCoeffVarReal) :: EndowQFieldQuantityCoeff  !! quantity (level) of each endowment q: field  
	  type (GPCoeffVarReal) :: EndowQFieldQuantityVar  !! change in quantity of each endowment (q: field) 
	  type (GPCoeffVarReal) :: EndowQFieldValueCoeff  !! value (level) of endowment
	  type (GPCoeffVarReal) :: EndowQFieldValueVar  !! %-change in value (level) of endowment
! Names are given for the example:
! $demand:ra
! e:plab  q:200
! EndowPriceVar is plab and EndowPriceCoeff is PLAB_L
! EndowQFieldQuantityCoeff is QS_RA_PLAB and EndowQFieldQuantityVar is p_qs_ra_plab [or c_qs_ra_plab]
! EndowQFieldValueCoeff is VS_RA_PLAB and EndowQFieldValueVar is p_vs_ra_plab [or c_vs_ra_plab]

! Next will be a real (eg q:200) or a Coefficient (eg q:totfac)
! Note that EndowQFieldQuantityCoeffOrRealMPSGE is not set up if QFieldIsExpression is true
	  type (GPCoeffVarReal) :: EndowQFieldQuantityCoeffOrRealMPSGE  !! MPSGE value (initial level) of endowment

! Now handle case where is an experssion in the q: field
	  logical :: QFieldIsExpression  !! Tells if QField is an expression
	  character (len=512) :: QFieldExpressionString   !! The expression in the q: field (if is such) 
	  logical :: QFieldNeedGEMPACKCoeff  !! Tells if need a separate GEMPACK coefficient for the q: field 

	  logical :: HasRField
! Next only set up if HasRField is true. The GEMPACK name for EndowRFieldCoeff is the same as in the MGE file.
! EndowRFieldVar is always a change variable with name c_<EndowRFieldCoeff>.
	  type (GPCoeffVarReal) :: EndowRFieldCoeff  !! level of r: variable
	  type (GPCoeffVarReal) :: EndowRFieldVar  !! change in level of r: variable

! EndowUnRationedQuantityCoeff/Var are of no economic interest - we have them purely to implement the MPSGE
!   idea of "rationing" 
	  type (GPCoeffVarReal) :: EndowUnrationedQuantityCoeff  !! unrationed quantity of endowment (level)
	  type (GPCoeffVarReal) :: EndowUnrationedQuantityVar  !! change in unrationed quantity of endowment
! Names are given for the example:
! $demand:ra
! e:plab  q:200  r:rls
! EndowPriceVar is plab
! EndowQFieldQuantityCoeff is QS_RA_PLAB and EndowQFieldQuantityVar is p_qs_ra_plab [or c_qs_ra_plab]
! EndowQFieldValueCoeff is VS_RA_PLAB and EndowQFieldValueVar is p_vs_ra_plab [or c_vs_ra_plab]
! EndowRFieldCoeff is RLS and EndowRFieldVar is c_RLS
! EndowUnrationedQuantityCoeff is US_RA_PLAB and EndowUnrationedQuantityVar is c_us_ra_plab.

! [04/04/04] These will be omitted
!	  type (GPCoeffVarReal) :: EndowRationedQuantityVar  !! %-change in quantity of each endowment  
!	  type (GPCoeffVarReal) :: EndowRationedQFieldValueCoeff  !! value (level) of endowment
!	  type (GPCoeffVarReal) :: EndowRationedQFieldValueVar  !! %-change in value (level) of endowment

	  type(endowmentGP), pointer :: next    !! Pointer to next in linked list of all endowmentGPs
	end type endowmentGP

        type (endowmentGP), pointer :: EndowmentGPList !! Pointer to the first endowmentGP in linked list
        type (endowmentGP), pointer :: EndowmentGPLast !! Pointer to the last endowmentGP in linked list

! For calling GEMPACK routines
	character (len=70) :: errmes

! For info about the HAR file [cf GEMPACK program SEEHAR]
	integer :: NumHeadOnHarFile
        character (len=llhd), dimension(:), allocatable :: HeadOnFile
        character (len=2), dimension(:), allocatable :: HeadTypeOnFile
	integer, parameter :: LLongNameHA=70 !! Length of a long name on a HAR file
        character (len=LLongNameHA), dimension(:), allocatable :: LongNameOnFile
        integer, dimension(:, :), allocatable :: SizeOnFile
        integer, dimension(:), allocatable :: CHLENOnFile
        character(len=3), dimension(:), allocatable :: StatusOnFile
! CoeffNadArgsOnFile - Coefficient name string (including set names)
        character (len=120), dimension(:), allocatable :: CoeffAndArgsOnFile
	integer, dimension(:), allocatable :: TPSTELOnFile
	

contains

	subroutine AddToGPNameList( Name, UserSystemType, CoeffVarType, Args)
! This adds at the end of GPNameList a GPName with the specified
!		Name, UserSystemType and Args
! Input
	character (len=*) Name, UserSystemType, CoeffVarType
	type (domain), pointer :: Args      ! Sets over which arguments range
! Local
	type (GPName), pointer :: ThisGPName
	type (domain), pointer :: FoundArgs
	logical :: Found
	character :: FoundUserSystemType

! [26/04/04] Check that this name is not already in the list - if so is error
!  to add it again
	call IsNameInGPNameList(Name, Found, FoundUserSystemType, FoundArgs)
	if(Found) then
	  call InternalErrorStop('AddToGPNameList. '//trim(Name)//' is already in GPNameList')
	end if   

	allocate(ThisGPName)
	ThisGPName%name = Name
	nullify(ThisGPName%next)
! Complete info in ThisGPName
	ThisGPName%UserSystemType = UserSystemType
	ThisGPName%type = CoeffVarType
	ThisGPName%arg => Args
	if(CoeffVarType.eq.'v') then
! Assume originally that all are exogenous. Mark ones as endogenous when write equation for them
	  ThisGPName%ExogEndogStatus = 'x'
	else
	  ThisGPName%ExogEndogStatus = ' '
	end if

	if(.not.associated(GPNameList)) then
	  GPNameList => ThisGPName
	  GPNameLast => ThisGPName
	else
	  GPNameLast%next => ThisGPName
	  GPNameLast => ThisGPName
	end if
	nullify(GPNameLast%next)

	return
	end subroutine AddToGPNameList

	subroutine AddToReadHeaderGPList( ThisHeader)
! This adds at the end of ReadHeaderGPListList a header
! Input
	character (len=*) ThisHeader
! Local
	type (HeaderGP), pointer :: NewHeaderGP

	allocate(NewHeaderGP)
	NewHeaderGP%Header = ThisHeader
	nullify(NewHeaderGP%next)

	if(.not.associated(ReadHeaderGPList)) then
	  ReadHeaderGPList => NewHeaderGP
	  ReadHeaderGPLast => NewHeaderGP
	else
	  ReadHeaderGPLast%next => NewHeaderGP
	  ReadHeaderGPLast => NewHeaderGP
	end if
	nullify(ReadHeaderGPLast%next)

	return
	end subroutine AddToReadHeaderGPList

	logical function IsInReadHeaderGPList(ThisString)
! Input
	character (len=*), intent(in) :: ThisString
! Local
	type (HeaderGP), pointer :: CurrentHeaderGP
	character (len=llhd) :: AbbrevString, Head2

	AbbrevString = ThisString

	CurrentHeaderGP => ReadHeaderGPList
	do while(associated(CurrentHeaderGP))
	  Head2 = CurrentHeaderGP%Header
!	  write(*,*)'IsInReadHeaderGPList. AbbrevString='//trim(AbbrevString)// &
!		' Head2 =',trim(head2)
	  if(EqualStringsIgnoreCase(AbbrevString, Head2)) then
	    IsInReadHeaderGPList = .true.
	    Return
	  end if

	  CurrentHeaderGP => CurrentHeaderGP%next
	end do

	IsInReadHeaderGPList = .false.
	return
	end function IsInReadHeaderGPList

	integer function LastVowel(ThisString)
! Marks position of last vowel in ThisString
! Input
	character (len=*), intent(in) :: ThisString
! Local
	character (len=512) :: TempString
	integer n1,n2,n3,n4,n5

	TempString = ThisString
	call lower(TempString)
	n1=INDEX(TempString, 'a', back=.true.)
	n2=INDEX(TempString, 'e', back=.true.)
	n3=INDEX(TempString, 'i', back=.true.)
	n4=INDEX(TempString, 'o', back=.true.)
	n5=INDEX(TempString, 'u', back=.true.)
	LastVowel = MAX(n1,n2,n3,n4,n5)
!	write(*,*)'LastVowel. ThisString=', trim(ThisString), ' Result=', LastVowel
	
	return
	end function LastVowel

	subroutine GetReadHeader(NameToRead, NewHeader)
! Input
	character (len=*), intent(in) :: NameToRead
! Output
	character (len=*), intent(out) :: NewHeader
! Must avoid any headers in ReadHeaderGPList
! Local
	type (HeaderGP), pointer :: CurrentHeader
	character (len=llhd) :: TryHead1, TryHead2
	character (len=512) :: ModName1, ModName2
	integer :: N1, i

!	write(*,*)'GetReadHeader. NameToRead=', trim(NameToRead)

! ViewHAR does not allow "_" or presumably "@" in header names when
!   edit the file interactively. So drop these.
	ModName1 = NameToRead
	call OmitAllOfSpecifiedString('_', ModName1)
	call OmitAllOfSpecifiedString('@', ModName1)

	if(LEN_TRIM(ModName1).le.llhd) then
	  TryHead1 = ModName1
	else

! Try omitting vowels from the right-hand end until get name of right length
! Do not omit the first letter if it is a vowel
	  do while(LEN_TRIM(ModName1).gt.4.and.LastVowel(ModName1).gt.1)
	    n1=LastVowel(ModName1)
	    if(n1.gt.0) then
	      if(n1.gt.1) then
	        ModName1=ModName1(1:n1-1)//ModName1(n1+1:)
	      end if
	      ModName1 = trim(ModName1)
	    end if
!	    write(*,*)'GetReadHeader. ModName1=', trim(ModName1)
	  end do
	  TryHead1 = ModName1
	end if

! Use TryHead1 if not already used
! [26/04/04] And if it is not a reserved header - begins with two xx
	if(.not.IsInReadHeaderGPList(TryHead1)) then
	 if(.not.EqualStringsIgnoreCase(TryHead1(1:2),'xx')) then
	  NewHeader = TryHead1
! Add this to ReadHeaderGPList
	  call AddToReadHeaderGPList( NewHeader)
	  Return
	 end if
	end if

! Here have not found a new one
! Replace characters at end of TryHead1 until get a new header
! Omit last character from TryHead1 and add digits at the end
	TryHead1 = TryHead1(1:3)
! [26/04/04] If first two characters are 'xx', add z at the start
	if(EqualStringsIgnoreCase(TryHead1(1:2),'xx')) then
	  TryHead1='z'//TryHead1(1:2)
	end if
	do i=1,9
	  TryHead1 = TryHead1(1:3)//trim(PosinttoString(i))
! Use TryHead1 if not already used
	  if(.not.IsInReadHeaderGPList(TryHead1)) then
	    NewHeader = TryHead1
! Add this to ReadHeaderGPList
	    call AddToReadHeaderGPList( NewHeader)
	    Return
	  end if
	end do

! For the present, return with fatal error
	call InternalErrorStop('GetReadHeader. Did not find new header.')

	return
	end subroutine GetReadHeader

	character (len=255) function ConstructGPName( CoeffVarType, UserSystemType, & 
		Args, SuggestedName, StartIfChangeName)
! [07/04/04] At present, StartIfChangeName is not used
! Input
! CoeffVarType is 'c' coeff, 'v' variable etc
! UserSystemType is 'u' (user name) or 's' (system name)
	character (len=*) CoeffVarType, UserSystemType, SuggestedName, StartIfChangeName
! Args
	type (domain), pointer :: Args      ! Sets over which arguments range
	

! Use type to work out max length. May change from SuggestedName if it is too long
! Will also change from suggested name if that name has already been used.
! Local
	character (len=LengthGPDeclarationName) TrialName, TrialName2
	type (GPName), pointer :: ThisGPName
	type (domain), pointer :: FoundArgs
	logical :: Found, Finished
	character :: FoundUserSystemType
	integer n1,n2,n3,n4,n5, i
	integer :: MaxAllowedLength, MaxUsed, MaxIntToTry
! NumDigits is number of digits add at end. [NumDigits must be at most 9.]
	integer, parameter :: NumDigitsToAdd = 4
	character (len=NumDigitsToAdd) :: AddString
	character :: NumDigitsChar
	character (len=12) :: CoeffVarString
!
! With system names, if SuggestedName is too long for the Type, make up another TrialName
! With user names, must not change them. Is error if name is too long
!
!	write(*,*) 'ConstructGPName: SuggestedName = ', SuggestedName
	Finished = .false.

! Set up MaxAllowedLength
	if(CoeffVarType.eq.'c') then
	    MaxAllowedLength = llcs
	    CoeffVarString = 'Coefficient'
	else if(CoeffVarType.eq.'v') then
	    MaxAllowedLength = llvc
	    CoeffVarString = 'Variable'
	end if

	if(UserSystemType.eq.'u') then
! Do not change name here, but truncate name if necessary
	  TrialName=SuggestedName
! Test if length is ok
	  if(LEN_TRIM(TrialName).gt.MaxAllowedLength) then
	    call ErrorStop('Sorry. User-supplied name "'//trim(TrialName)// &
			'" is too long for a GEMPACK '//trim(CoeffVarString)//'.'// &
			'\n Please shorten it.') 
	  end if
	  ConstructGPName = TrialName
	  Finished = .true.
	  goto 120
	end if
	
! 1. Try omitting ?()"" from TrialName. Then try it
	TrialName = SuggestedName
10	continue
	n1=INDEX(TrialName, '(')
	n2=INDEX(TrialName, ')')
	n3=INDEX(TrialName, '"')
	n4=INDEX(TrialName, '"')
	n5=INDEX(TrialName, '?')
	n1=MAX(n1,n2,n3,n4,n5)
	if(n1.gt.1) then
	  TrialName = TrialName(1:n1-1)//TrialName(n1+1:)
! Try this again
	  goto 10
	end if
! See if TrialName is already one of the names in the list
	call IsNameInGPNameList(TrialName, Found, FoundUserSystemType, FoundArgs)
	if(.not.Found.and.LEN_TRIM(TrialName).le.MaxAllowedLength) then
	  ConstructGPName = TrialName
	  Finished = .true.
	end if

	if(.not.Finished) then
! 2. Try replacing ("<text>") by ?, then replacing ? by integers until get a new one
	  TrialName = SuggestedName
20	  continue
	  n1=INDEX(TrialName, '("')
	  if(n1.gt.1) then
	    n2=INDEX(TrialName(n1+1:),'")')
	    if(n2.gt.0) then
! N2 is position in TrialName(n1+1:), which omits first N1 characters of TrialName. 
!  Hence that is position N1+N2 in TrialName 
	      TrialName=TrialName(1:n1-1)//'?'//TrialName(n1+n2+2:)
! Try this again
	      goto 20
	    end if
	  end if
! Are there any "?". If so, expect just one "?" (but omit later ones if present)
25	  continue
	  n1=INDEX(TrialName,'?')
	  n2=INDEX(TrialName,'?',back=.true.)
	  if(n2.gt.n1) then
! Are two "?". Omit the latter one and try again
	    TrialName=TrialName(1:n2-1)//TrialName(n2+1:)
	    goto 25
	  end if
	  if(n1.gt.1) then
	    if(n2.eq.n1) then
	      TrialName2 = TrialName
	      do i=1,99
	       if(.not.Finished) then
	        TrialName=TrialName2(1:n1-1)//trim(posinttostring(i))//TrialName2(n1+1:)
! See if TrialName is already one of the names in the list
	        call IsNameInGPNameList(TrialName, Found, FoundUserSystemType, FoundArgs)
	        if(.not.Found.and.LEN_TRIM(TrialName).le.MaxAllowedLength) then
	          ConstructGPName = TrialName
	          Finished = .true.
	        end if
	       end if ! if(.not.Finished) then
	      end do
	    end if
	  end if
	end if ! if(.not.Finished) then
!
	if(.not.Finished) then
! Try omitting the last few characters (if necessary) and then adding digits
!  at the end to get a new name
	  TrialName = SuggestedName
	  n1=LEN_TRIM(TrialName)
! At present, use 4 digits 0001,0002 etc
! Start adding digits after position MaxUsed in TrialName
	  MaxUsed=MIN(n1,MaxAllowedLength-NumDigitsToAdd)
	  NumDigitsChar = PosintToString(NumDigitsToAdd)
	  MaxIntToTry = 10**NumDigitsToAdd - 1  ! eg, MaxIntTry is 9999 when NumDigitsToAdd=4

!temporary
!	  write(*,*)'TrialName(1:n1) is:',TrialName(1:n1)
!	  write(*,*)'TrialName(1:Maxused) is:',TrialName(1:MaxUsed)

	  i = 0
	  do while(.not.Finished .and. i.lt.MaxIntToTry)
	      i = i + 1
	      write(AddString, '(I'//NumDigitsChar//'.'//NumDigitsChar//')') i
	      TrialName2 = TrialName(1:MaxUsed)//AddString
! See if TrialName2 is already one of the names in the list
	      call IsNameInGPNameList(TrialName2, Found, FoundUserSystemType, FoundArgs)
	      if(.not.Found.and.LEN_TRIM(TrialName2).le.MaxAllowedLength) then
	        ConstructGPName = TrialName2
	        Finished = .true.
	      end if
	  end do ! do while(.not.Finished .and. i.lt.MaxIntToTry)
	end if ! if(.not.Finished) then
 
! Run out of options
	if(.not.Finished) then
	    call ErrorStop( &
	      'ConstructGPName. Constructing a system name.'// &
	      '\n SuggestedName='//trim(SuggestedName)//'. Need to make up a new name')
	end if
!
!   Here have found new name.
!
!	write(*,*)'ConstructGPName. Name used is: ',trim(ConstructGPName)

! Jump here in the user case
120	continue


!  Add this name to those already in GPNameList if it is not already there
	call IsNameInGPNameList(ConstructGPName, Found, FoundUserSystemType, FoundArgs)
	if(.not.Found) then
	  call AddToGPNameList( ConstructGPName, UserSystemType, CoeffVarType, Args)
	end if
!
	return
	end function ConstructGPName

	subroutine IsNameInGPNameList(TrialName, Found, FoundUserSystemType, FoundArgs)
! Input
	character (len=*) TrialName
! Output
	logical :: Found
	character (len=*) :: FoundUserSystemType  ! Only set if Found is true
	type (domain), pointer :: FoundArgs
! Local
	type (GPName), pointer :: ThisGPName
	character (len=LengthGPDeclarationName) TrialName2, ThisName
!
	Found = .false.
	FoundUserSystemType = ' '
	nullify(FoundArgs)

	ThisGPName => GPNameList

! trim TrialName and also shorten it to max allowed and put in lower case for
!		string comparison
	TrialName2 = trim(TrialName)

	do while(associated(ThisGPName).and. .not.Found)
	  ThisName = ThisGPName%name
	  ThisName = trim(ThisName)
	  if(EqualStringsIgnoreCase(TrialName2, ThisName)) then
	    Found = .true.
	    FoundUserSystemType = ThisGPName%UserSystemType
	    FoundArgs => ThisGPName%arg
	  end if
	  ThisGPName => ThisGPName%next
	end do

	end subroutine IsNameInGPNameList

	subroutine AddToGPReadList( Name)
! This adds at the end of GPReadList a GPRead with the specified
!		Name
! Input
	character (len=*) Name
!??	type (domain), pointer :: Args      ! Sets over which arguments range
! Local
	type (GPRead), pointer :: ThisGPRead
	logical :: Found

! Should not do this if the name is already in the list
	call IsNameInGPReadList(Name, Found)
	if(Found) then
	  call InternalErrorStop('AddToGPReadList. '//trim(Name)//' is already in the list.')
	end if

	allocate(ThisGPRead)
	ThisGPRead%name = Name
	nullify(ThisGPRead%next)
! Complete info in ThisGPRead
!??	ThisGPRead%arg => Args

	if(.not.associated(GPReadList)) then
	  GPReadList => ThisGPRead
	  GPReadLast => ThisGPRead
	else
	  GPReadLast%next => ThisGPRead
	  GPReadLast => ThisGPRead
	end if
	nullify(GPReadLast%next)

	return
	end subroutine AddToGPReadList

	subroutine IsNameInGPReadList(TrialName, Found)
! Input
	character (len=*) TrialName
! Output
	logical :: Found
! Local
	type (GPRead), pointer :: ThisGPRead
	character (len=LengthGPDeclarationName) TrialName2
!
	Found = .false.

	ThisGPRead => GPReadList

! trim TrialName and also shorten it to max allowed.
	TrialName2 = trim(TrialName)

	do while(associated(ThisGPRead).and. .not.Found)
	  if(EqualStringsIgnoreCase(TrialName2,ThisGPRead%name)) then
	    Found = .true.
	  end if
	  ThisGPRead => ThisGPRead%next
	end do ! do while(associated(ThisGPRead).and. .not.Found)

	return
	end subroutine IsNameInGPReadList

	subroutine ConvertElastToGPCoeffReal(SOrTType, FunctionString, &
			ElastField, ThisElasticity, ThisElasticityIsConstant)
! Input
	character (len=*) :: SOrTType  ! 's' or 't'  (only used in labelling info)
	character (len=*) :: FunctionString   ! eg "$prod:y(s)" (only used in labelling info)
	type (field), pointer :: ElastField
! Output
	type (GPCoeffVarReal) :: ThisElasticity
	logical :: ThisElasticityIsConstant
! Local
	character (len=255) ElastText
	type (symbol), pointer :: ElastSymbol
!
	ElastText = trim(ElastField%data)

	if(IsReal(ElastText)) then

	  call InitializeGPCoeffVarReal('r', ThisElasticity)
	  ThisElasticity%name = ElastText
	  ThisElasticityIsConstant = .true.

!	 End "if(IsReal(ElastText)) then"
	else

	  call InitializeGPCoeffVarReal('c', ThisElasticity)
	  if(associated(ElastField%ident)) then
	    ThisElasticity%name = ElastField%ident%name
	  else
! Next should be unnecessary ??
!	    write(*,*)'ThisElasticity: ElastField%ident not associated'
	    ThisElasticity%name = ElastField%identtext
! Try to add %ident for this field ElastField
	    call findid(trim(ElastField%identtext), ElastSymbol)
	    if(associated(ElastSymbol)) then
		write(*,*)' Elasticity ident added for ', trim(ElastField%identtext),' - KP'
		ElastField%ident => ElastSymbol
	    end if 
	  end if
	  ThisElasticity%arg => ElastField%arg
	  ThisElasticity%labelinfo = SOrTType//' elasticity in '//trim(FunctionString)
	  ThisElasticity%IsParam = .true.
	  ThisElasticityIsConstant = .false.

!	 End "if(IsReal(ElastText)) then..else.."
	end if

	return
	end subroutine ConvertElastToGPCoeffReal

	subroutine AddToFunctionGPList( ThisFunctionGP)
! This adds ThisFunctionGP at the end of FunctionGPList
! Input
	type (FunctionGP), pointer :: ThisFunctionGP

	if(associated(FunctionGPList)) then
	      FunctionGPLast%next => ThisFunctionGP
	else
	      FunctionGPList => ThisFunctionGP
	end if
	FunctionGPLast => ThisFunctionGP 
	nullify(FunctionGPLast%next)

	return
	end subroutine AddToFunctionGPList

	subroutine AddToNetputGPList( ThisNetputGP)
! This adds ThisNetputGP at the end of NetputGPList
! Input
	type (NetputGP), pointer :: ThisnetputGP

	if(associated(NetputGPList)) then
	      netputGPLast%next => ThisnetputGP
	else
	      NetputGPList => ThisNetputGP
	end if
	NetputGPLast => ThisNetputGP 
	nullify(NetputGPLast%next)

	return
	end subroutine AddToNetputGPList

	subroutine AddToTaxGPList( ThisTaxGP)
! This adds ThisTaxGP at the end of TaxGPList
! Input
	type (TaxGP), pointer :: ThisTaxGP

	if(associated(TaxGPList)) then
	      TaxGPLast%next => ThisTaxGP
	else
	      TaxGPList => ThisTaxGP
	end if
	TaxGPLast => ThisTaxGP 
	nullify(TaxGPLast%next)

	return
	end subroutine AddToTaxGPList

	subroutine AddToEndowmentGPList( ThisEndowmentGP)
! This adds ThisEndowmentGP at the end of EndowmentGPList
! Input
	type (EndowmentGP), pointer :: ThisEndowmentGP

	if(associated(EndowmentGPList)) then
	      EndowmentGPLast%next => ThisEndowmentGP
	else
	      EndowmentGPList => ThisEndowmentGP
	end if
	EndowmentGPLast => ThisEndowmentGP 
	nullify(EndowmentGPLast%next)

	return
	end subroutine AddToEndowmentGPList

	character function ProdSDChar(IsOutput)
!  Supply/Demand character for a o: or i: line in a $prod 
! Input
	logical, intent(in) :: IsOutput

! Either 's' (output) and 'd' (input) OR
!        'o' (output) and 'i' (input)
	if(IsOutput) then
	  ProdSDChar = 's'
	else
	  ProdSDChar = 'd'
	end if

	return
	end function ProdSDChar

	subroutine WriteSymbolList
! Local
	type (symbol), pointer :: CurrentSymbol

!	write(*,*)' Calling WriteSymbolLlist'
	CurrentSymbol => idlist
	do while(associated(CurrentSymbol))
!	  write(*,*)'Symbol name:', trim(CurrentSymbol%name), ' Symbol type:', trim(CurrentSymbol%type)
	  CurrentSymbol => CurrentSymbol%next
	end do
	
	return
	end subroutine WriteSymbolList

	subroutine AnalyseField(CurrentField, FieldIsExpression, FieldExpressionString)
! Analyse a field (eg q:, t:, p:) field. See if is expression in this field. See if will need
!  GEMPACK Coeff to stand for this field. Set up FieldCoeffOrRealMPSGE.
! Input
	type(field), pointer :: CurrentField
! Output
	logical, intent(out) :: FieldIsExpression
	character (len=*), intent(out) :: FieldExpressionString
! Local
	integer :: n1
	logical :: TempLog

! Initialize
	FieldIsExpression = .false.
! [26/04/04] Always initialise the expression string, even if is a single coeff
	FieldExpressionString = CurrentField%data

	if(CurrentField%data(1:1).eq.'(') then
! %data should start with '(' and end with ')'. Strip them off.
	  n1=LEN_TRIM(CurrentField%data)
	  FieldExpressionString = CurrentField%data(2:n1-1)
	  FieldIsExpression = .true.
	end if

	if(CurrentField%data(1:1).eq.'-') then
! Sometimes have "-coeff" in q: field in e: line. All of %data is the expression in this case
! And sometimes have negative real number in q: field (eg q:-20)
	  if(IsLetter(CurrentField%data(2:2))) then
	    FieldExpressionString = CurrentField%data
	    FieldIsExpression = .true.
	  else
! Check to see that the whole field is a valid number
	    TempLog = numeric(trim(CurrentField%data))
	  end if
	end if

	if(INDEX(CurrentField%data,'"').gt.0) then
! Contains a quoted element. Treat this as an expression.
	  FieldExpressionString = CurrentField%data
!	  write(*,*) 'FieldExpressionString is: ', trim(FieldExpressionString)
	  FieldIsExpression = .true.
	end if

	return
	end subroutine AnalyseField

	subroutine GetQFieldValueCoeffEtc( &
! Input
	  CurrentQField, &
! CurrentLineField is the field from i:, o: or e: at start of line
! It is CurrentIOField in IO case
	  CurrentLineField, & 
! CurrentLineDomain is CurrentNetput%d in IO case
	  CurrentLineDomain, &
! FunctionAbbreviation is variable name after $prod: or $demand: [eg is "y" in "$prod:y(s)"]
! FunctionString is $prod: or $demand: followed by variable plus arguments [eg is "$prod:y(s)"]
	  FunctionAbbreviation, FunctionString, &
! SupplyDemandEndowmentChar is SupplyDemandChar in IO case
! LineChar is InputOutputChar in IO case
	  SupplyDemandEndowmentChar, LineChar, &
! LineHasRField can only be true if are doing e: line
	  LineHasRField, & 
! Output
! QFieldQuantityCoeff is NewNetputGP%IOQuantityCoeff in IO case
! QFieldQuantityVar is NewNetputGP%IOQFieldQuantityVar in IO case
	  QFieldQuantityCoeff, & 
	  QFieldQuantityVar, & 
! QFieldValueCoeff is NewNetputGP%IOQFieldValueCoeff in IO case
! QFieldValueVar is NewNetputGP%IOQFieldValueVar in IO case
	  QFieldValueCoeff, QFieldValueVar, &
! QFieldArgGP is NewNetputGP%IOArgGP in IO case (equals QFieldValeCoeff%arg at present)
	  QFieldArgGP, &      
! QFieldQuantityCoeffOrRealMPSGE is NewNetputGP%IOQFieldQuantityCoeffOrRealMPSGE in IO case
	  QFieldQuantityCoeffOrRealMPSGE, &
! QFieldIsExpression tells if QField is an expression
! QFieldExpressionString - the expression in the q: field (if is such)
	  QFieldIsExpression, QFieldExpressionString, QFieldNeedGEMPACKCoeff, &
	  LinePriceAbbrev)
!

! Input
	type (field), pointer :: CurrentQField, CurrentLineField
	type (domain), pointer :: CurrentLineDomain
	character (len=*), intent(in) :: FunctionAbbreviation, &
	  FunctionString, SupplyDemandEndowmentChar, LineChar
! LineHasRField can only be true if are doing e: line
	logical, intent(in) :: LineHasRField
! Output
	type (GPCoeffVarReal), intent(out) :: QFieldQuantityCoeff, QFieldValueCoeff, QFieldQuantityVar 
	type (GPCoeffVarReal), intent(out) :: QFieldQuantityCoeffOrRealMPSGE, QFieldValueVar
	type (domain), pointer :: QFieldArgGP 
	logical, intent(out) :: QFieldIsExpression
	logical, intent(out) :: QFieldNeedGEMPACKCoeff 
	character (len=*), intent(out) :: QFieldExpressionString 
	character (len=*), intent(out) :: LinePriceAbbrev 
	
! Local
	logical :: DomainIsFull, LinePriceIsFullDomain
	type (domain), pointer :: LineFieldArg, LinePriceFullArg
	type (GPCoeffMPSGE), pointer :: GPCoeffMPSGEFound
	integer :: n1, NumTimesFound
	character :: UQChar, PCChar
	logical :: IsELine, Found, TempLog, GiveUpdateWarning

! This must work for i: or o: line in $prod or for e: line in $demand
	
!	write(*,*)'Calling GetQFieldValueCoeffEtc'

! Initialize
	IsELine = (CurrentLineField%label.eq.'e').or.(CurrentLineField%label.eq.'E')

! [26/04/04] Call routine AnalyseField to set up QFieldIsExpression and QFieldExpressionString
! [26/04/04] Note that routine AnalyseField always sets up QFieldExpressionString, even if
!  QFieldIsExpression is false.
	call AnalyseField(CurrentQField, QFieldIsExpression, QFieldExpressionString)

! Look at CurrentLineField and work out if the arguments of the price there
!  are ranging over the full sets as in the declaration of this price in the
!   $commodities part of the file
	LineFieldArg => CurrentLineField%arg
	LinePriceFullArg => CurrentLineField%ident%arg
	if(.not.associated(LinePriceFullArg)) then
	  LinePriceIsFullDomain = .true.
	else
	  LinePriceIsFullDomain = subset(LineFieldArg, LinePriceFullArg) .and. &
				subset(LinePriceFullArg, LineFieldArg)
	end if
! Use LinePriceAbbrev in making up names
	if(LinePriceIsFullDomain) then
	  LinePriceAbbrev = CurrentLineField%identtext   ! eg pf
	else
	  LinePriceAbbrev = CurrentLineField%data        ! eg pf(f1) or pf("lab") or pi("lab",s)
! Do not want to include the condition, so stop if find $
	  n1=index(LinePriceAbbrev,'$')
	  if(n1.gt.0) LinePriceAbbrev = LinePriceAbbrev(1:n1-1)
	end if

!	write(*,*)'GetQFieldValueCoeffEtc. CurrentLineField is '//trim(CurrentLineField%label)//':'// &
!	  trim(CurrentLineField%data)
!	write(*,*)'LinePriceAbbrev is: ', LinePriceAbbrev
	
! QFieldQuantityCoeff
! [04/04/04] Now associate QFieldQuantityCoeff with the expression in the q: field since that
!  represents a quantity, not a value (at least in the e: line case)
!QUANT indicates changes made in this connection

! Use what the user gives us if that is of full rank. To check this, compare
!		  CurrentQField%arg and CurrentNetput%d
! Otherwise make up a name

!    QFieldNeedGEMPACKCoeff tells if need a GEMPACK Coeff which is different from
!		the MPSGE symbol. This is true if the MPSGE symbol is
!		 numeric (eg "2.1"), in which case it is not in the symbol
!		  table idlist, or if the two domains are not the same.

		QFieldNeedGEMPACKCoeff = .false.

! If e: line has r: field, need a gempack coeff
!NO		if(IsEline.and.LineHasRField) then
!NO		  NeedGEMPACKCoeff = .true.
		
! If Q field is an expression, need a gempack coeff
		if(QFieldIsExpression) then
		  QFieldNeedGEMPACKCoeff = .true.

		else		

! Note by KP. a real constant (eg "2.1" as in "q:2.1") is not added to the symbol table.
!  See the use of the logical function "numeric" in Tom's code.
!		  write(*,*)'Calling numeric, pos 1'
		  if(numeric(CurrentQField%data)) QFieldNeedGEMPACKCoeff = .true.
!		  write(*,*)'Called numeric, pos 1'

		end if

! [10/04/04] QFieldNeedGEMPACKCoeff must be set true if the Coefficient name in this q: field
!   occurs in more than one field in the MGE file
		if(.not.QFieldNeedGEMPACKCoeff) then
		  call IsInGPCoeffMPSGEList(CurrentQField%identtext, Found, GPCoeffMPSGEFound)
		  if(Found) then
	            NumTimesFound = GPCoeffMPSGEFound%NumTimesFound
		    if(NumTimesFound.gt.1) then
		      QFieldNeedGEMPACKCoeff = .true.
		    end if
		  else
		    call InternalErrorStop('GetQFieldValueCoeffEtc. Name '//trim(CurrentQField%identtext)//' not found.')
		  end if
		end if ! if(.not.QFieldNeedGEMPACKCoeff) then

		if(.not.QFieldNeedGEMPACKCoeff) then

!  Test if the two domains are the same
		  DomainIsFull = .false.
! If no sets in CurrentNetput%d then DomainIsFull must be true
! IO case		  if(.not.associated(CurrentNetput%d)) then
		  if(.not.associated(CurrentLineDomain)) then
		    DomainIsFull = .true.
		  else
! IO case	    if(.not.IsSubdomainIgnoreOrder(CurrentQField%arg, CurrentNetput%d)) then
		    if(.not.IsSubdomainIgnoreOrder(CurrentQField%arg, CurrentLineDomain)) then
!		      This is an error
		      call ErrorStop('Q field domain is not a subset of Line domain')
		    end if
! IO case	    DomainIsFull = IsSubdomainIgnoreOrder(CurrentNetput%d, CurrentQField%arg)
		    DomainIsFull = IsSubdomainIgnoreOrder(CurrentLineDomain, CurrentQField%arg)
		  end if
		  if(.not.DomainIsFull) QFieldNeedGEMPACKCoeff = .true.

!		 End "if(.not.QFieldNeedGEMPACKCoeff) then"
		end if

! IO case       call InitializeGPCoeffVarReal('c', NewNetputGP%IOQFieldValueCoeff)
!QUANT	        call InitializeGPCoeffVarReal('c', QFieldValueCoeff)
	        call InitializeGPCoeffVarReal('c', QFieldQuantityCoeff)

! Set up UQChar
		if(LineHasRField) then
! Unrationed quantity
		  UQChar = 'U'
		else
		  UQChar = 'Q'
		end if

		if (.not.QFieldNeedGEMPACKCoeff) then
!
!!		    NewNetputGP%IOQFieldValueCoeff%name = CurrentQField%ident%name 
! Use call to ConstructGPName to that this name is added to GPNameList  
! IO case	    NewNetputGP%IOQFieldValueCoeff%name = ConstructGPName('c', 'u', CurrentNetput%d, &
!QUANT		    QFieldValueCoeff%name = ConstructGPName('c', 'u', CurrentLineDomain, &
		    QFieldQuantityCoeff%name = ConstructGPName('c', 'u', CurrentLineDomain, &
		      CurrentQField%ident%name, ' ')
! IO case	    NewNetputGP%IOQFieldValueCoeff%arg => CurrentQField%arg
!QUANT		    QFieldValueCoeff%arg => CurrentQField%arg
		    QFieldQuantityCoeff%arg => CurrentQField%arg
!
!		 End "if (.not.QFieldNeedGEMPACKCoeff) then"
		else
!
! IO case	  NewNetputGP%IOQFieldValueCoeff%name = ConstructGPName('c', 's', CurrentNetput%d, &
! IO case	    'V'//SupplyDemandChar//'_'//trim(FunctionAbbreviation)// &
! IO case	    '_'//trim(CurrentLineField%ident%name), 'V'//SupplyDemandChar)
! [01/04/04] If have multiple lines with different parts of the same price 
!     (eg i:pf("lab") and i:pf("cap") or i:pf(f1) where f1 ranges over a subset of f)
! put this into SuggestedName. Routine ConstructGPName replaces these suitably in trying
!  to get a suitable new name.
! So use LinePriceAbbrev in place of CurrentLineFile%ident%name to give ConstructGPName flexibility 
!    to handle multiple lines with different parts of the same price 

!QUANT		  QFieldValueCoeff%name = ConstructGPName('c', 's', CurrentLineDomain, &
		  QFieldQuantityCoeff%name = ConstructGPName('c', 's', CurrentLineDomain, &
! [03/04/04] Drop the "V" at the start since the associated variable QFieldValueVar may have this name
! WAS		    'V'//SupplyDemandEndowmentChar//'_'//trim(FunctionAbbreviation)// &
! [04/04/04] Add "Q"/"U" at start
!QUANT		    SupplyDemandEndowmentChar//'_'//trim(FunctionAbbreviation)// &
		    UQChar//SupplyDemandEndowmentChar//'_'//trim(FunctionAbbreviation)// &
! WAS - old	    '_'//trim(CurrentLineField%ident%name), 'V'//SupplyDemandEndowmentChar)
! WAS		    '_'//trim(LinePriceAbbrev), 'V'//SupplyDemandEndowmentChar)
!QUANT		    '_'//trim(LinePriceAbbrev), SupplyDemandEndowmentChar)
		    '_'//trim(LinePriceAbbrev), UQChar//SupplyDemandEndowmentChar)

! IO case	  NewNetputGP%IOQFieldValueCoeff%arg => CurrentNetput%d 
!QUANT		  QFieldValueCoeff%arg => CurrentLineDomain 
		  QFieldQuantityCoeff%arg => CurrentLineDomain 

! Don't give a warning if is expression starting with "("

		  GiveUpdateWarning = .true.
	          if(CurrentQField%data(1:1).eq.'(') GiveUpdateWarning = .false.

		  if(GiveUpdateWarning) then
		    call GiveWarning(trim(CurrentQField%data)// &
			' will not be updated - better to add full rank symbol here and to read it.')
		  end if
!
!		 End "if (.not.QFieldNeedGEMPACKCoeff) then..else.."
		end if
! IO case       call upper(NewNetputGP%IOQFieldValueCoeff%name)   ! Convert name to upper case
!QUANT	        call upper(QFieldValueCoeff%name)   ! Convert name to upper case
	        call upper(QFieldQuantityCoeff%name)   ! Convert name to upper case
! IO case	NewNetputGP%IOQFieldValueCoeff%labelinfo = & 
! IO case		    'Value (levels) of quantity for '//InputOutputChar//':'//trim(CurrentIOField%data)// &
!QUANT		QFieldValueCoeff%labelinfo = & 
!QUANT		    'Value (levels) of quantity for '//LineChar//':'//trim(CurrentLineField%data)// &
!QUANT		    ' in '//trim(FunctionString)
		if(LineHasRField) then
		  QFieldQuantityCoeff%labelinfo = & 
		    'Rationed quantity (level - no economic meaning) in q: field of '//LineChar//':'//trim(CurrentLineField%data)// &
		    ' in '//trim(FunctionString)
		else
		  QFieldQuantityCoeff%labelinfo = & 
		    'Quantity (level) in q: field of '//LineChar//':'//trim(CurrentLineField%data)// &
		    ' in '//trim(FunctionString)
!  or should it be - ie, give the o: field or the q: field 
!		    'Value (levels) of quantity for '//'q:'//trim(CurrentQField%data)// &
		end if

!-----------------------------------------------------------------------------------------------
! [04/04/04] Now do QFieldValueCoeff - as for QFieldQuantityCoeff with slight differences
	        call InitializeGPCoeffVarReal('c', QFieldValueCoeff)
! Now always a system name
		QFieldValueCoeff%name = ConstructGPName('c', 's', CurrentLineDomain, &
! [03/04/04] Drop the "V" at the start since the associated variable QFieldValueVar may have this name
! WAS		    'V'//SupplyDemandEndowmentChar//'_'//trim(FunctionAbbreviation)// &
! [04/04/0] Drop first "_" to stop getting long too quickly
!DROP		    SupplyDemandEndowmentChar//'_'//trim(FunctionAbbreviation)// &
		    'V'//SupplyDemandEndowmentChar//'_'//trim(FunctionAbbreviation)// &
! WAS - old	    '_'//trim(CurrentLineField%ident%name), 'V'//SupplyDemandEndowmentChar)
! WAS		    '_'//trim(LinePriceAbbrev), 'V'//SupplyDemandEndowmentChar)
		    '_'//trim(LinePriceAbbrev), 'V'//SupplyDemandEndowmentChar)
		QFieldValueCoeff%arg => QFieldQuantityCoeff%arg 
		QFieldValueCoeff%labelinfo = & 
		    'Value (levels) of quantity for '//LineChar//':'//trim(CurrentLineField%data)// &
		    ' in '//trim(FunctionString)
!-----------------------------------------------------------------------------------------------

! [14/04/04] In ELine, QFieldQuantityCoeff and QFieldValueCoeff can be negative
		if(IsELine) then
		  QFieldQuantityCoeff%IsGE0 = .false.
		  QFieldValueCoeff%IsGE0 = .false.
		end if


! Set NewNetputGP%IOArgGP - same as NewNetputGP%IOQFieldValueCoeff%arg. Use IOArgGP elsewhere in case
!  later we need to make IOArgGP different from IOQFieldValueCoeff%arg. See the note where
!   IOArgGP is defined under type (netputGP).
! [Do not use CurrentNetput%d because, although these are the right sets, they may be in a different order. See
!    the examples where IOArgGP is defined under type (netputGP).]

! IO case	NewNetputGP%IOArgGP => NewNetputGP%IOQFieldValueCoeff%arg 
		QFieldArgGP => QFieldQuantityCoeff%arg 

! QFieldQuantityVar.
! Set up PCChar. When is e: line, make this (and other variables) Change variables if
!  there is an r: field. [That is because the levels value of the r: field variable can be zero.]
!	 Otherwise make this a %-change variables.
! [14/04/04] In e: line, q: field can be negative as well as positive. So always make
!  it a change variable
!WAS		if(IsELine.and.LineHasRField) then
		if(IsELine) then
		  PCChar = 'c' ! QFieldQuantityVar and QFieldValueVar are change variables
		else
		  PCChar = 'p' ! QFieldQuantityVar and QFieldValueVar are %-change variables
		end if
 
! [06/04/04] The names of the variables are always derived from the corresponding coefficient
!  by adding p_ or c_ at the start.
! QFieldQuantityVar
	        call InitializeGPCoeffVarReal('v', QFieldQuantityVar)
		QFieldQuantityVar%name = ConstructGPName('v', 's', QFieldArgGP, &
		      PCChar//'_'//QFieldQuantityCoeff%name, ' ')
	        call lower(QFieldQuantityVar%name)   ! Convert name to lower case
		QFieldQuantityVar%arg => QFieldArgGP 
		QFieldQuantityVar%VarType = PCChar 
		if(LineHasRField) then
		    QFieldQuantityVar%labelinfo = & 
		      'change in unrationed quantity (no economic meaning) for '//LineChar//':'//&
		      trim(CurrentLineField%data)//' in '//trim(FunctionString)
		else if(IsELine) then
! [14/04/04] is a change variable - see above
		    QFieldQuantityVar%labelinfo = & 
		      'change in quantity for '//LineChar//':'//&
		      trim(CurrentLineField%data)//' in '//trim(FunctionString)
		else
		    QFieldQuantityVar%labelinfo = & 
		      '%-change in quantity for '//LineChar//':'//&
		      trim(CurrentLineField%data)//' in '//trim(FunctionString)
		end if
		QFieldQuantityVar%OrigLevel = QFieldQuantityCoeff%name

! QFieldQuantityVar
	        call InitializeGPCoeffVarReal('v', QFieldValueVar)
		QFieldValueVar%name = ConstructGPName('v', 's', QFieldArgGP, &
		      PCChar//'_'//QFieldValueCoeff%name, ' ')
	        call lower(QFieldValueVar%name)   ! Convert name to lower case
		QFieldValueVar%arg => QFieldArgGP 
		QFieldValueVar%VarType = PCChar 
		if(PCChar.eq.'c') then
		    QFieldValueVar%labelinfo = & 
		      'change in value for '//LineChar//':'//&
		      trim(CurrentLineField%data)//' in '//trim(FunctionString)
		else if(PCChar.eq.'p') then
		    QFieldValueVar%labelinfo = & 
		      '%-change in value for '//LineChar//':'//&
		      trim(CurrentLineField%data)//' in '//trim(FunctionString)
		end if
	        call lower(QFieldQuantityVar%name)   ! Convert name to lower case
		QFieldValueVar%OrigLevel = QFieldValueCoeff%name

! QFieldQuantityCoeffOrRealMPSGE - what the user gives as the initial quantity
! [31/03/04] If QFieldIsExpression, do not (cannot) set up QFieldQuantityCoeffOrRealMPSGE

		if(.not.QFieldIsExpression) then

!		  write(*,*)'Calling numeric, pos 2'
		 if(numeric(CurrentQField%data)) then
! IO case         call InitializeGPCoeffVarReal('r', NewNetputGP%IOQFieldQuantityCoeffOrRealMPSGE)
! IO case	  NewNetputGP%IOQFieldQuantityCoeffOrRealMPSGE%name = CurrentQField%data
	          call InitializeGPCoeffVarReal('r', QFieldQuantityCoeffOrRealMPSGE)
		  QFieldQuantityCoeffOrRealMPSGE%name = CurrentQField%data

		 else

! IO case         call InitializeGPCoeffVarReal('c', NewNetputGP%IOQFieldQuantityCoeffOrRealMPSGE)
	          call InitializeGPCoeffVarReal('c', QFieldQuantityCoeffOrRealMPSGE)
! IO case	  NewNetputGP%IOQFieldQuantityCoeffOrRealMPSGE%name = &
		  QFieldQuantityCoeffOrRealMPSGE%name = &
		    ConstructGPName('c', 'u', CurrentQField%arg, CurrentQField%ident%name, ' ')
! IO case	  NewNetputGP%IOQFieldQuantityCoeffOrRealMPSGE%arg => CurrentQField%arg
		  QFieldQuantityCoeffOrRealMPSGE%arg => CurrentQField%arg
! IO case	  NewNetputGP%IOQFieldQuantityCoeffOrRealMPSGE%labelinfo = &
! IO case	    'Pre-simulation Value of quantity for '//InputOutputChar//':'//trim(CurrentIOField%data)
		  QFieldQuantityCoeffOrRealMPSGE%labelinfo = &
		    'Pre-simulation quantity for '//LineChar//':'//trim(CurrentLineField%data)
! IO case	  NewNetputGP%IOQFieldQuantityCoeffOrRealMPSGE%IsParam = .true.

! QFieldQuantityCoeffOrReal is not a parameter if IsELine and LineHasRField
		  if(.not.(IsELine.and.LineHasRField)) then
		    QFieldQuantityCoeffOrRealMPSGE%IsParam = .true.
		  end if ! if(.not.(IsELine.and.LineHasRField)) then

		 end if ! if(numeric(CurrentQField%data)) then..else..

!		 write(*,*)'Called numeric, pos 2'
		end if ! if(.not.QFieldIsExpression) then

!	write(*,*)'Ended GetQFieldValueCoeffEtc'
	

	return
	end subroutine GetQFieldValueCoeffEtc

	subroutine AddToSetGPList( SetName)
! This adds at the end of SetGPList a SetGP with the specified name
! Input
	character (len=*) SetName
! Local
	type (SetGP), pointer :: ThisSetGP

	allocate(ThisSetGP)
	ThisSetGP%name = SetName
	nullify(ThisSetGP%next)

	if(.not.associated(SetGPList)) then
	  SetGPList => ThisSetGP
	  SetGPLast => ThisSetGP
	else
	  SetGPLast%next => ThisSetGP
	  SetGPLast => ThisSetGP
	end if
	nullify(SetGPLast%next)

	return
	end subroutine AddToSetGPList

	subroutine BuildSetGPList

! Local
	type(symbol), pointer :: CurrentSymbol
	type(SetGP), pointer :: NewSetGP, SetGPLast

	NumSets = 0
	nullify(SetGPList)
	nullify(SetGPLast)
	CurrentSymbol => idlist
	do while(associated(CurrentSymbol))  
	  if(CurrentSymbol%type.eq.'set') then
	    NumSets = NumSets + 1
!	    write(*,*)'BuildSetGPList. CurrentSymbol%name is:', trim(currentSymbol%name)
	    call AddToSetGPList(CurrentSymbol%name)
	  end if
	  CurrentSymbol => CurrentSymbol%next
	end do ! while(associated(CurrentSymbol))

	return  
	end subroutine BuildSetGPList

	integer function GetSetNumber(ThisSetName)
! Input
	character (len=*) :: ThisSetName
! Local
	type(setGP), pointer :: CurrentSetGP
	integer :: CurrentSetNumber

	CurrentSetGP => SetGPList
	CurrentSetNumber = 0
	do while(associated(CurrentSetGP))
	  CurrentSetNumber = CurrentSetNumber + 1
	  if(EqualStringsIgnoreCase(ThisSetName, CurrentSetGP%name)) then
	    GetSetNumber = CurrentSetNumber
	    return
	  end if

	  CurrentSetGP => CurrentSetGP%next
	end do ! while(associated(CurrentSetGP))
! Here did not find the set
	GetSetNumber = 0
!  Re-initialize 'pre' messages again at start of each function
	call InitializeMessages('pre',0)
	call InternalErrorStop('GetSetNumber. Did not find set '//trim(ThisSetName)//' in SetGPList.')

	return
	end function GetSetNumber
	
	character (len=llst) function GetSetName(ThisSetNumber)
! Input

	integer, intent(in) :: ThisSetNumber
! Local
	type(setGP), pointer :: CurrentSetGP
	integer :: CurrentSetNumber

	CurrentSetGP => SetGPList
	CurrentSetNumber = 0
	do while(associated(CurrentSetGP))
	  CurrentSetNumber = CurrentSetNumber + 1
	  if(CurrentSetNumber.eq.ThisSetNumber) then
	    GetSetName = CurrentSetGP%name
	    return
	  end if

	  CurrentSetGP => CurrentSetGP%next
	end do ! while(associated(CurrentSetGP))
! Here did not find the number
	GetSetName = ''
!  Re-initialize 'pre' messages again at start of each function
	call InitializeMessages('pre',0)
	call InternalErrorStop('GetSetName. ThisSetNumber is out of range.')

	return
	end function GetSetName

	subroutine GetSetSymbol(ThisSetName, ThisSetSymbol)
! input
	character (len=*) :: ThisSetName
! output
	type(symbol), pointer :: ThisSetSymbol
! Local
	type(symbol), pointer :: CurrentSymbol
	logical :: Found

! Run through idlist, looking for this set
	Found = .false.
	CurrentSymbol => idlist
	do while(associated(CurrentSymbol).and. .not.Found)
	  if(CurrentSymbol%type.eq.'set') then
	    if(EqualStringsIgnoreCase(ThisSetName,CurrentSymbol%name)) then
		Found = .true.
		ThisSetSymbol => CurrentSymbol
	    end if
	  end if
	  CurrentSymbol => CurrentSymbol%next
	end do ! while(associated(CurrentSymbol).and. .not.Found)
	if(.not.Found) then
	  call InternalErrorStop('Set '//trim(ThisSetName)//' not found in idlist.')
	end if

	return
	end subroutine GetSetSymbol

	character (len=llst) function GetSingletonSetName(QuotedElement)
! Input
	character (len=*) :: QuotedElement
! Local
	integer :: n1
	character (len=llst) :: Name1

	n1=LEN_TRIM(QuotedElement)
! For the present, just add "S" to the element name. Later should check
!   that this is a new set.

	Name1 = 's'//QuotedElement(2:n1-1)
	call upper(Name1)
	GetSingletonSetName = Name1

	return
	end function GetSingletonSetName

	subroutine GetNewGPCoeffMPSGE(ThisGPCoeffMPSGE)
! Input
	type(GPCoeffMPSGE), pointer :: ThisGPCoeffMPSGE

	nullify(ThisGPCoeffMPSGE)
	allocate(ThisGPCoeffMPSGE)
	ThisGPCOeffMPSGE%Name = ''
!NO	nullify(ThisGPCoeffMPSGE%Symbol)
	nullify(ThisGPCoeffMPSGE%MaxArg)
	ThisGPCoeffMPSGE%NumTimesFound = 0
	
	return
	end subroutine GetNewGPCoeffMPSGE

	subroutine AddToGPCoeffMPSGEList( ThisGPCoeffMPSGE)
! This adds ThisGPCoeffMPSGE at the end of GPCoeffMPSGEList
! Input
	type(GPCoeffMPSGE), pointer :: ThisGPCoeffMPSGE
! Local

	if(.not.associated(GPCoeffMPSGEList)) then
	  GPCoeffMPSGEList => ThisGPCoeffMPSGE
	  GPCoeffMPSGELast => ThisGPCoeffMPSGE
	else
	  GPCoeffMPSGELast%next => ThisGPCoeffMPSGE
	  GPCoeffMPSGELast => ThisGPCoeffMPSGE
	end if
	nullify(GPCoeffMPSGELast%next)

	return
	end subroutine AddToGPCoeffMPSGEList

	subroutine IsInGPCoeffMPSGEList(ThisCoeffName, Found, GPCoeffMPSGEFound)
! Input
	character (len=*), intent(in) :: ThisCoeffName
! Output
	logical, intent(out) :: Found
	type (GPCoeffMPSGE), pointer :: GPCoeffMPSGEFound
! Local
	type(GPCoeffMPSGE), pointer :: CurrentGPCoeffMPSGE

	Found = .false.
	nullify(GPCoeffMPSGEFound)
	CurrentGPCoeffMPSGE => GPCoeffMPSGEList
	do while(associated(CurrentGPCoeffMPSGE).and. .not.Found)
	  if(EqualStringsIgnoreCase(ThisCoeffName, CurrentGPCoeffMPSGE%Name)) then
	    Found = .true.
	    GPCoeffMPSGEFound => CurrentGPCoeffMPSGE
	  end if
	  CurrentGPCoeffMPSGE => CurrentGPCOeffMPSGE%next 
	end do ! while(associated(CurrentGPCoeffMPSGE).and. .not.Found)

! Test result is as expected
	if(Found) then
	  if(.not.EqualStringsIgnoreCase(ThisCoeffName, GPCoeffMPSGEFound%name)) then
	    call InternalErrorStop('IsInGPCoeffMPSGEList. Name problem')
	  end if
	end if

	return
	end subroutine IsInGPCoeffMPSGEList
 
	subroutine UpdateOneArg(CurrentMaxArg, CurrentArgumentNumber, NewInfoSetName)
! Are building up list of max sets used with GPCoefficientMPSGEs
! CurrentMaxSet is largest set used in this position so far
! NewInfoSet is set in this position now.
! Try to find a set for which both CurrentMaxSet and NewInfoSetName are subsets
! If, for example, CurrentMaxSet is "lab" and NewInfoSet is "cap", new CurrentMaxSet is FACT. 
! Input/Output
	type(domain), pointer :: CurrentMaxArg
! Input
	integer, intent(in) :: CurrentArgumentNumber
	character (len=*), intent(in) :: NewInfoSetName
! Local
	integer :: MaxArgSetNumber, NewInfoSetNumber, i, ThisArgumentNumber
	type(symbol), pointer :: ThisSetSymbol
	type(domain), pointer :: CurrentMaxSet, CurrentLastSet
	logical :: SetFound
	character (len=1024) :: OutputText
	integer :: LenOutput

	call GetThisArgNumber(CurrentMaxArg, CurrentArgumentNumber, CurrentMaxSet)
!	if(associated(CurrentMaxSet)) then
!	  write(*,*)'UpdateOneArg. CurrentMaxSet is associated. CurrentArgumentNumber = ', CurrentArgumentNumber
!	else
!	  write(*,*)'UpdateOneArg. CurrentMaxSet is not associated. CurrentArgumentNumber = ', CurrentArgumentNumber
!	end if

!	write(*,*)'Writing GPCoeffMPSGEList at start of UpdateOneArg'
!	call WriteGPCoeffMPSGEList
!	write(*,*)'Written GPCoeffMPSGEList at start of UpdateOneArg'

! CurrentMaxSet is relevant argument in CurrentMaxArg	
	if(.not.associated(CurrentMaxSet)) then
! CurrentMaxSet becomes NewInfoSet and ThisSet (the previous argument) points to this
	      call newdomain(CurrentMaxSet)
! Find this set in idlist
	      call findid(NewInfoSetName, ThisSetSymbol)
	      CurrentMaxSet%s => ThisSetSymbol
	      if(associated(CurrentMaxArg)) then
!	        call WriteArguments(CurrentMaxArg, OutputText, LenOutput)
!	        write(*,*)'UpdateOneArg. Original CurrentMaxArg is:',trim(OutputText(1:LenOutput))
	        call GetThisArgNumber(CurrentMaxArg, CurrentArgumentNumber-1, CurrentLastSet)
! This new one ThisSetSymbol is the next after the current last one [CurrentLastSet] in CurrentMaxArg
		CurrentLastSet%next => CurrentMaxSet
	      else if(.not.associated(CurrentMaxArg)) then
!	        write(*,*)'UpdateOneArg. Original CurrentMaxArg null'
! This should be the first time have encountered this name as a GPCoeffMPSGE. Expect this
!   is the first argument. Allocate CurrentMaxarg and point it to CurrentMaxSet as its first argument.
	        if(CurrentArgumentNumber.eq.1) then
		  call newdomain(CurrentMaxArg)
		  CurrentMaxArg => CurrentMaxSet
		else
		  call InternalErrorStop('UpdateOneArg. CurrentArgumentNumber exceeds 1.')
		end if
	      end if ! else if(.not.associated(CurrentMaxArg)) then
!	      call WriteArguments(CurrentMaxArg, OutputText, LenOutput)
!	      write(*,*)'UpdateOneArg. New CurrentMaxArg is:',trim(OutputText(1:LenOutput))
	else if(associated(CurrentMaxSet)) then
! Is New one a known subset of CurrentMaxArg set? If so no change to make
	      MaxArgSetNumber = GetSetNumber(CurrentMaxSet%s%name)
	      NewInfoSetNumber = GetSetNumber(NewInfoSetName)
	      if(NewInfoSetNumber.eq.MaxArgSetNumber) then
! Nothing to do
	      else if(IsSubsetGP(NewInfoSetNumber,MaxArgSetNumber)) then
! Nothing to do
	      else if(IsSubsetGP(MaxArgSetNumber,NewInfoSetNumber)) then
! Max is now NewInfo
		call findid(NewInfoSetName, ThisSetSymbol)
		CurrentMaxSet%s => ThisSetSymbol		 
	      else
! Try to find a set which both are subsets of. For example, may have encountered
!  endow("lab") before and now encounter endow("cap"). Should find set containing
!  both "lab" and "cap" and set MaxArgSet equal to this set
! Run through the sets, looking for a set containing both
	        SetFound = .false.
	        do i=1,NumSets
		  if(IsSubsetGP(MaxArgSetNumber,i).and.IsSubsetGP(NewInfoSetNumber,i)) then
		    SetFound = .true.
! Find this set number I amongst the sets in idlist
	            call GetSetSymbol(GetSetName(i), ThisSetSymbol)
		    CurrentMaxSet%s => ThisSetSymbol
		    write(*,*)'UpdateOneArg. Sets ',trim(CurrentMaxSet%s%name),' and ', trim(NewInfoSetName)
		    write(*,*)'- found set ',trim(ThisSetSymbol%name), ' for which are a common subset.'
		  end if
	        end do ! i=1,NumSets
	        if(.not.SetFound) then
! Not sure what to do. At present this probably should be an error
		  write(*,*)'NewInfoSetName is ',trim(NewInfoSetName), ' CurrentMaxSet is ', &
		    trim(CurrentMaxSet%s%name)
		  write(*,*)'CurrentArgumentNumber is', CurrentArgumentNumber
		  call InternalErrorStop('UpdateOneArg. Could not find big set containing both.')
	        end if
	      end if
	end if ! else if(associated(CurrentMaxSet)) then

!	write(*,*)'Writing GPCoeffMPSGEList at end of UpdateOneArg'
!	call WriteGPCoeffMPSGEList
!	write(*,*)'Written GPCoeffMPSGEList at end of UpdateOneArg'

	return
	end subroutine UpdateOneArg

	subroutine UpdateMaxArg(CurrentMaxArg, NewInfoArg)
! Input/Output
	type(domain), pointer :: CurrentMaxArg
! Input
	type(domain), pointer :: NewInfoArg
! Local
	integer :: CurrentArgNumber, MaxArgSetNumber, NewInfoSetNumber, i
	type(domain), pointer :: CurrentMaxArgSet, CurrentNewInfoArgSet
	type(symbol), pointer :: ThisSetSymbol
	logical :: SetFound
	character (len=1024) :: OutputText
	integer :: LenOutput

! Expect number of sets in CurrentMaxArg and NewInfoArg to be the same
	CurrentArgNumber = 0
	CurrentMaxArgSet => CurrentMaxArg
	CurrentNewInfoArgSet => NewInfoArg
	do while(associated(CurrentMaxArgSet))
	  if(.not.associated(CurrentNewInfoArgSet)) then
	    call InternalErrorStop('UpdateMaxArg. CurrentNewInfoArgSet is null.')
	  end if
	  CurrentArgNumber = CurrentArgNumber + 1
	  call UpdateOneArg(CurrentMaxArg, CurrentArgNumber, CurrentNewInfoArgSet%s%name)
!	  call WriteArguments(CurrentMaxArg, OutputText, LenOutput)
!	  write(*,*)'UpdateMaxArg. New CurrentMaxArg is:',trim(OutputText(1:LenOutput))
	  CurrentNewInfoArgSet => CurrentNewInfoArgSet%next 
	  CurrentMaxArgSet => CurrentMaxArgSet%next 
	end do ! while(associated(CurrentMaxArg))

	return
	end subroutine UpdateMaxArg

	subroutine AddFieldToGPCoeffMPSGEList(CurrentField)
! Input
	type(field), pointer :: CurrentField
! Local
	type(GPCoeffMPSGE), pointer :: CurrentGPCoeffMPSGE, NewGPCoeffMPSGE, GPCoeffMPSGEHere, GPCoeffMPSGEFound
	logical :: AlreadyInList, DoNothing, IsExpression, Found, AddThisToNumTimesFound
	character (len=1024) ::ThisGPExpression
	character (len=1024) :: OutputText
	integer :: LenOutput
	character (len=10) :: str1, str2
	integer :: NumArgHere, NumArgFound

! Do nothing if the text in this field is an expression or a number
	DoNothing = .false.

	IsExpression = .false.
	if(CurrentField%identtext(1:1).eq.'(') IsExpression = .true.
! Not sure how to treat "-" and NumTimesFound
	if(CurrentField%identtext(1:1).eq.'-') then
! Sometimes have "-coeff" in q: field in e: line. All of %data is the expression in this case
! And sometimes have negative real number in q: field (eg q:-20)
! [See GetQFieldValueCoeffEtc]
	  if(IsLetter(CurrentField%identtext(2:2))) then
	    IsExpression = .true.
! [Otherwise, the whole field should be a valid number]
	  end if
	end if

!NO At present, only count this in NumTimesFound when find it not in an expression. [Not sure if this is correct.]
! At present, always add to NumTimesFound. [Otherwise, have an order problem if coeff
!  appears in an expression in a function before it appears as a levels variable in a later block.]

! [16/04/04] Now do two passes, only declaring and reading things in GPCoeffMPSGEList 
!  on the first pass (when GPCoeffMPSGEPass is true). So can revert to only adding to
!  NumTimesFound when find it not in an expression. 
! ** THIS IS IMPORTANT **
!WAS	AddThisToNumTimesFound = .true.
	AddThisToNumTimesFound = .not.IsExpression

!NO	if(.not.IsExpression) then
!NO	  if(INDEX(CurrentField%data,'"').gt.0) IsExpression = .true.
!NO	end if

	if(.not.IsExpression) then
	  if(numeric(CurrentField%identtext)) DoNothing = .true.
	end if
	if(DoNothing) return

! Get the GPCoeffMPSGEs into GPCoeffMPSGEHere.
! Do this by processing the expression  which is in CurrentField%data 
	ThisGPExpression = ExpressionToGPSyntax(CurrentField%data, GPCoeffMPSGEHere)
! Run through those in GPCoeffMPSGEHere. If already in list, add to NumTimesFound if relevant
!  If not already in list, add to the list
!	write(*,*) 'AddFieldToGPCoeffMPSGEList. Beginning to process GPCoeffMPSGEHere'

	CurrentGPCoeffMPSGE => GPCoeffMPSGEHere
	do while(associated(CurrentGPCoeffMPSGE))

!	  write(*,*) 'AddFieldToGPCoeffMPSGEList. Processing ', trim(CurrentGPCoeffMPSGE%Name)
!	  write(*,*)'Writing GPCoeffMPSGEList'
!	  call WriteGPCoeffMPSGEList
!	  write(*,*)'Written GPCoeffMPSGEList'

	  call IsInGPCoeffMPSGEList(CurrentGPCoeffMPSGE%Name, Found, GPCoeffMPSGEFound)
	  if(Found) then

! Check that the number of arguments this time equals the number found previously. If not,
! is a user error
	    NumArgHere = GetArgDim(CurrentGPCoeffMPSGE%MaxArg) 
	    NumArgFound = GetArgDim(GPCoeffMPSGEFound%MaxArg)
	    if(NumArgHere.ne.NumArgFound) then
!  [Note that PosintToString can process zero ok.]
	      str1 = PosintToString(NumArgHere)
	      str2 = PosintToString(NumArgFound)
	      call ErrorStop(trim(CurrentGPCoeffMPSGE%Name)//' has '//trim(str1)//' arguments here.'// &
		'\n Elsewhere in the MGE file it has '//trim(str2)//' arguments.')  	 
	    end if ! if(NumArgHere.ne.NumArgFound) then

	    if(AddThisToNumTimesFound) then
	      GPCoeffMPSGEFound%NumTimesFound = GPCoeffMPSGEFound%NumTimesFound + 1
	    end if
! Update MaxArg on the basis of what we find here
!	    write(*,*)'AddFieldToGPCoeffMPSGEList. Calling UpdateMaxArg. GPCoeffMPSGEFound%Name is:', trim(GPCoeffMPSGEFound%Name)
!	    call WriteArguments(GPCoeffMPSGEFound%MaxArg, OutputText, LenOutput)
!	    write(*,*)'AddFieldToGPCoeffMPSGEList. Before UpdateMaxArg. CurrentMaxArg is:',trim(OutputText(1:LenOutput))
	    call UpdateMaxArg(GPCoeffMPSGEFound%MaxArg, CurrentGPCoeffMPSGE%MaxArg)
!	    call WriteArguments(GPCoeffMPSGEFound%MaxArg, OutputText, LenOutput)
!	    write(*,*)'AddFieldToGPCoeffMPSGEList. After UpdateMaxArg. New CurrentMaxArg is:',trim(OutputText(1:LenOutput))

!	    write(*,*)'Writing GPCoeffMPSGEList after UpdateMaxArg call'
!	    call WriteGPCoeffMPSGEList
!	    write(*,*)'Written GPCoeffMPSGEList after UpdateMaxArg call'

	  else

! Add this to GPCoeffMPSGEList
!	    write(*,*) 'AddFieldToGPCoeffMPSGEList. Adding ',trim(CurrentGPCoeffMPSGE%Name), ' to GPCoeffMPSGEList'

	    call GetNewGPCoeffMPSGE(NewGPCoeffMPSGE)
	    NewGPCoeffMPSGE%Name = CurrentGPCoeffMPSGE%Name
	    NewGPCoeffMPSGE%MaxArg => CurrentGPCoeffMPSGE%MaxArg
!	    call WriteArguments(NewGPCoeffMPSGE%MaxArg, OutputText, LenOutput)
!	    write(*,*)'AddFieldToGPCoeffMPSGEList. Initial MaxArg is:',trim(OutputText(1:LenOutput))
	    if(AddThisToNumTimesFound) then
	      NewGPCoeffMPSGE%NumTimesFound = 1
	    else
	      NewGPCoeffMPSGE%NumTimesFound = 0
	    end if
	    call AddToGPCoeffMPSGEList( NewGPCoeffMPSGE)
	  end if
	  CurrentGPCoeffMPSGE => CurrentGPCoeffMPSGE%next
	end do ! do while(associated(CurrentGPCoeffMPSGE))

!	write(*,*) 'AddFieldToGPCoeffMPSGEList. Ended processing of GPCoeffMPSGEHere'
!	write(*,*)'Writing GPCoeffMPSGEList at end of AddFieldToGPCoeffMPSGEList'
!	call WriteGPCoeffMPSGEList
!	write(*,*)'Written GPCoeffMPSGEList at end of AddFieldToGPCoeffMPSGEList'

! OLD CODE NOW NOT USED IS BELOW
! Run through the list, seeing if this is in it. If so update MaxArg if necessary
!OLD	AlreadyInList = .false.
!OLD	CurrentGPCoeffMPSGE => GPCoeffMPSGEList
!OLD	do while(associated(CurrentGPCoeffMPSGE))
!NO	  if(EqualStringsIgnoreCase(CurrentGPCoeffMPSGE%Symbol%name,CurrentField%identtext)) then
!OLD	  if(EqualStringsIgnoreCase(CurrentGPCoeffMPSGE%Name,CurrentField%identtext)) then
!OLD	    AlreadyInList = .true.
!OLD	    CurrentGPCoeffMPSGE%NumTimesFound = CurrentGPCoeffMPSGE%NumTimesFound + 1
! Update MaxArg on the basis of what we find here
!OLD	    write(*,*)'Calling UpdateMaxArg. CurrentGPCoeffMPSGE%Name is:', trim(CurrentGPCoeffMPSGE%Name)
!OLD	    call UpdateMaxArg(CurrentGPCoeffMPSGE%MaxArg, CurrentField%arg)
!OLD	  end if
!OLD	  CurrentGPCoeffMPSGE => CurrentGPCoeffMPSGE%next
!OLD	end do ! while(associatedCurrentGPCoeffMPSGE)

!OLD	if(.not.AlreadyInList) then
! Add this to the list
!OLD	  call GetNewGPCoeffMPSGE(NewGPCoeffMPSGE)
!OLD	  NewGPCoeffMPSGE%Name = CurrentField%ident%name
!NO	  NewGPCoeffMPSGE%Symbol => CurrentField%ident
!OLD	  NewGPCoeffMPSGE%MaxArg => CurrentField%arg
!OLD	  NewGPCoeffMPSGE%NumTimesFound = 1
!OLD	  call AddToGPCoeffMPSGEList( NewGPCoeffMPSGE)
!OLD	end if

	return
	end subroutine AddFieldToGPCoeffMPSGEList

	subroutine WriteGPCoeffMPSGEList

! Local
	type(GPCoeffMPSGE), pointer :: CurrentGPCoeffMPSGE
	character (len=1024) :: OutputText
	integer :: LenOutput

	write(*,*)'Beginning WriteGPCoeffMPSGEList'

	CurrentGPCoeffMPSGE => GPCoeffMPSGEList
	do while(associated(CurrentGPCoeffMPSGE))
	  write(*,*)'WriteGPCoeffMPSGEList. Symbol is ', trim(CurrentGPCoeffMPSGE%Name), &
		' NumTimesFound is ', CurrentGPCoeffMPSGE%NumTimesFound
	  call WriteArguments(CurrentGPCoeffMPSGE%MaxArg, OutputText, LenOutput)
	  write(*,*)'Arguments are:', trim(OutputText(1:LenOutput))
	  
	  CurrentGPCoeffMPSGE => CurrentGPCoeffMPSGE%next
	end do ! while(associated(CurrentGPCoeffMPSGE))

	write(*,*)'Ended WriteGPCoeffMPSGEList'

	return
	end subroutine WriteGPCoeffMPSGEList

	subroutine BuildGPCoeffMPSGEList

! This also infers all subsets from the MPSGE version of functionlist etc
! Note that FunctionGPList is not set up at this stage, so cannot use it
! Local
	type (field), pointer :: fnf
	logical :: OtherFieldsPresent
	type (record), pointer :: r
	type (function), pointer :: fnMPSGE
	type (nest), pointer :: n
	type (netputlist), pointer :: e
	type (nest), pointer :: inputs, outputs
	type (domain), pointer :: InputsSubDomain
	type (domain), pointer :: TempDomain, FunctionDomain
	logical :: IsProd, IsDemand
	type(domain), pointer :: LinePriceArg
	type(symbol), pointer :: LinePriceSymbol, ThisSymbol
	type (netputlist), pointer :: CurrentElements
	type (netput), pointer :: CurrentNetPut
	type (field), pointer :: CurrentIOField, CurrentQField, CurrentEndowField
	type (domain), pointer :: CurrentIODomain, CurrentIOSubdomain
	type (taxlist), pointer :: CurrentTaxList, FirstTaxList, CurrentTaxList2
	type (endowmentlist), pointer :: CurrentEndowmentList
	type (endowment), pointer :: CurrentEndowment
	type (domain), pointer :: CurrentEndowmentDomain
	character (len=128) :: FunctionString, FunctionAbbreviation
	integer :: kpass, BigPass
	character :: InputOutputChar
	logical :: AreSomeTaxes

	nullify(GPCoeffMPSGEList)

! Allocate IsSubsetGP array
	allocate(IsSubsetGP(NumSets,NumSets))
! Initialise it all to false
	IsSubsetGP = .false.

! Run through the functions, working out any implied subsets when BigPass=1
! Build up GPCoeffMPSGEList when BigPass=2.

	do BigPass=1,2
	 fnMPSGE => functionlist
	 do while (associated(fnMPSGE))
	  r => fnMPSGE%firstrecord
	  fnf => r%firstfield

	  IsProd = fnf%label.eq.'$prod'
	  IsDemand = fnf%label.eq.'$demand'

	  FunctionString = trim(fnf%label)//':'//trim(fnf%data)
!	  write(*,*)'BuildGPCoeffMPSGEList. Processing ', trim(FunctionString)

!  Re-initialize 'pre' messages again at start of each function
	  call InitializeMessages('pre',0)
	  Messages%PreLine(1) = 'Processing function '//trim(fnf%label)//':'//trim(fnf%data)

	  if (IsProd) then

! Example
! $prod:y(s)          s:sigma(s)         
!  o:p(s)            q:supply(s)
!  i:pf(f)           q:factor(f,s)

	    FunctionAbbreviation = fnf%identtext  ! [eg is "y" in "$prod:y(s)"]
	    FunctionAbbreviation = trim(FunctionAbbreviation)
	    FunctionDomain => fnf%arg    ! [eg is "s" in "$prod:y(s)"]

	    if(BigPass.eq.1) then
! Check arguments against those used when $prod: activity variable was declared
! here it has arguments fnf%arg. The activity variable is fnf%ident
! [The activity variable is declared in the $sectors: part]
	      call InferSubsetsGP(fnf%arg,fnf%ident%arg)
! [18/04/04] According to syntax rules for this version of MPSGE, each sector can
!  only occur in one $prod: block.
! In this version of MGE2XX, do not allow $ in sector declaration. Hence can
!  infer that the sets are equal.
! Example. y(s) in the $sector declaration and $prod:y(o). Can infer s=o.
! Above call to InferSubsetsGP inferred that o is a subset of s. Now make
!  the other inference.
	      call InferSubsetsGP(fnf%ident%arg,fnf%arg)
	    end if

! Now go through its O: and I: lines adding coeff and var ($prod)
	    do kpass = 1,2
! Do outputs on pass 1, inputs on pass 2
	      if(kpass.eq.1) then
	        CurrentElements => fnMPSGE%outputs%elements
		InputOutputChar = 'o'
	      else if(kpass.eq.2) then
	        CurrentElements => fnMPSGE%inputs%elements
		InputOutputChar = 'i'
	      end if

! Run through the netputs of this type
	      do while(associated(CurrentElements))
	        CurrentNetput => CurrentElements%np
		CurrentIOField => CurrentNetput%f
		CurrentQField => CurrentNetput%qref
		CurrentIODomain => CurrentNetput%d
		CurrentIOSubdomain => CurrentNetput%sd
		CurrentTaxList => CurrentNetput%t
		AreSomeTaxes = associated(CurrentTaxList)

	        Messages%PreLine(2) = 'Processing line beginning '// &
			InputOutputChar//':'//trim(CurrentIOField%data)
!  Re-initialize 'pre' messages past number 2
	        call InitializeMessages('pre',2)
!		write(*,*)'BuildGPCoeffMPSGEList. ', trim(Messages%PreLine(2))

! Look at price at the start of this line. Infer subsets from this.

	        LinePriceArg => CurrentIOField%arg
	        LinePriceSymbol => CurrentIOField%ident

		if(BigPass.eq.1) then
! Check arguments against those used when IOFieldPriceName was declared
	          call InferSubsetsGP(LinePriceArg,LinePriceSymbol%arg)
		end if


! i: or o: line
! Look at q: field
! q: field
	        Messages%PreLine(3) = 'Processing "'// &
			trim(CurrentQField%label)//':'//trim(CurrentQField%data)//'"'
!  Re-initialize 'pre' messages past number 3
	        call InitializeMessages('pre',3)
!		write(*,*)'BuildGPCoeffMPSGEList. ', trim(Messages%PreLine(3))

		if(BigPass.eq.2) then
		  call AddFieldToGPCoeffMPSGEList(CurrentQField)
!		  write(*,*)'BuildGPCoeffMPSGEList. Called AddFieldtoGPCoeffMPSGEList.'
! [26/04/04] If there is a p: field in this line, add it
		  if(associated(CurrentNetput%pref)) then
		    call AddFieldToGPCoeffMPSGEList(CurrentNetput%pref)
		  end if
		end if

! Taxes for this netput

		if(AreSomeTaxes.and. .not.associated(CurrentTaxList)) then
		  call InternalErrorStop('AreSomeTaxes problem')
		end if

		do while(associated(CurrentTaxList))



! At present this GEMPACK conversion cannot handle M: or N: fields in tax stuff
!		  if(associated(CurrentTaxList%m).or.associated(CurrentTaxList%n)) then
!		    call ErrorStop('Sorry, ths program cannot handle m: or n: tax fields at present.')
!		  end if
! Details of this tax type
! For GEMPACK use, can ignore the p: field (CurrentNetput%pref)

!		  write(*,*)'BuildGPCoeffMPSGEList. Processing taxes on this line.'

		  if(BigPass.eq.2) then
! process the t: field or the m:/n: field pair
		    if(associated(CurrentTaxList%t)) then
	              Messages%PreLine(4) = 'Processing "'// &
			trim(CurrentTaxList%t%label)//':'//trim(CurrentTaxList%t%data)//'"'
		    else if(associated(CurrentTaxList%m)) then
	              Messages%PreLine(4) = 'Processing "'// &
			trim(CurrentTaxList%m%label)//':'//trim(CurrentTaxList%m%data)//'"'
		    end if
!  Re-initialize 'pre' messages past number 4
	            call InitializeMessages('pre',4)
!		    write(*,*)'BuildGPCoeffMPSGEList. ', trim(Messages%PreLine(4))

		    if(associated(CurrentTaxList%t)) then
		      call AddFieldToGPCoeffMPSGEList(CurrentTaxList%t)
		    else if(associated(CurrentTaxList%m)) then
! m: field
		      call AddFieldToGPCoeffMPSGEList(CurrentTaxList%m)
! n: field
	              Messages%PreLine(4) = 'Processing "'// &
			trim(CurrentTaxList%n%label)//':'//trim(CurrentTaxList%n%data)//'"'
		      call AddFieldToGPCoeffMPSGEList(CurrentTaxList%n)
		    end if

		  end if

		  CurrentTaxList => CurrentTaxList%next 
		end do  ! while(associated(CurrentTaxList))

!		write(*,*)'BuildGPCoeffMPSGEList. Processed taxes on this line.'

		CurrentElements => CurrentElements%next
	      end do

!	      write(*,*)'BuildGPCoeffMPSGEList. Ended KPASS=', kpass

	    end do ! kpass loop

!	   End "if (IsProd) then"
	  else if (IsDemand) then

	    FunctionAbbreviation = fnf%identtext  ! [eg is "y" in "$prod:y(s)"]
	    FunctionAbbreviation = trim(FunctionAbbreviation)
	    FunctionDomain => fnf%arg    ! [eg is "s" in "$prod:y(s)"]

	    if(BigPass.eq.1) then
! Check arguments against those used when $demand: income variable was declared
! here it has arguments fnf%arg. The income variable is fnf%ident
! [The income variable is declared in the $consumers: part]
	      call InferSubsetsGP(fnf%arg,fnf%ident%arg)
! [18/04/04] According to syntax rules for this version of MPSGE, each consumer can
!  only occur in one $demand: block.
! In this version of MGE2XX, do not allow $ in consumer declaration. Hence can
!  infer that the sets are equal.
! Example. ra(h) in the $consumer declaration and $demand:ra(g). Can infer h=g.
! Above call to InferSubsetsGP inferred that g is a subset of h. Now make
!  the other inference.
	      call InferSubsetsGP(fnf%ident%arg,fnf%arg)
	    end if

! Example
! $demand:ra
!  d:pc              q:cons
!  e:pf(f)           q:endow(f)

	    CurrentEndowmentList => fnMPSGE%endowments

! Run through the endowments in this list
	    do while(associated(CurrentEndowmentList))
	        CurrentEndowment => CurrentEndowmentList%e
		CurrentQField => CurrentEndowment%q
		CurrentEndowmentDomain => CurrentEndowment%d
	        CurrentEndowField => CurrentEndowment%f

	        Messages%PreLine(2) = 'Processing line beginning '// &
			'e:'//trim(CurrentEndowField%data)
!  Re-initialize 'pre' messages past number 2
	        call InitializeMessages('pre',2)

	        LinePriceArg => CurrentEndowField%arg
	        LinePriceSymbol => CurrentEndowField%ident

		if(BigPass.eq.1) then
! Check arguments against those used when IOFieldPriceName was declared
	          call InferSubsetsGP(LinePriceArg,LinePriceSymbol%arg)
		end if

! q: field
	        Messages%PreLine(3) = 'Processing "'// &
			trim(CurrentQField%label)//':'//trim(CurrentQField%data)//'"'
!  Re-initialize 'pre' messages past number 3
	        call InitializeMessages('pre',3)
		if(BigPass.eq.2) then
		  call AddFieldToGPCoeffMPSGEList(CurrentQField)
		end if

	        CurrentEndowmentList => CurrentEndowmentList%next
	    end do 

!	   End "if (IsProd) then..else if(IsDemand) then.."
	  end if

!	  write(*,*)'BuildGPCoeffMPSGEList. Processed ', trim(FunctionString)

	  fnMPSGE => fnMPSGE%next
	 end do ! do while (associated(fnMPSGE))

	  if(BigPass.eq.1) then
! Write the subsets
	    call WriteSubsets
	  end if

!----------------------------------------------------------------------
! [26/04/04] When BigPass=2, maybe should run through the $constaint equations, adding
!  any symbols occurring there which are not central variables to GPCoeffMPSGEList.
! See the notes in routine DoConstraints about adding symbols occurring there to
!  GPCoeffMPSGEList. At present are not doing this. If, later, decide have to do it,
!     perhaps could call routine DoConstraints with suitable logical flags passed in.
!?LATER?	  call DoConstraints(??)
!----------------------------------------------------------------------

	end do ! do BigPass=1,2
	
	end subroutine BuildGPCoeffMPSGEList

	subroutine WriteSubsets
! Local
	integer :: SmallSet, BigSet, set1, set2
	character (len=llst) :: SmallSetName, BigSetName

	do set1=1,NumSets
	  do set2 = 1,NumSets
	    if(IsSubsetGP(set1,set2)) then
	      SmallSet = set1
	      BigSet = set2
	      SmallSetName = GetSetName(SmallSet) 
	      BigSetName = GetSetName(BigSet)
!	      write(*,*)'Set number ', Smallset, ' ', trim(SmallSetName), &
!		' is a subset of set number ', BigSet, ' ', trim(BigSetName)
	    end if ! if(IsSubsetGP(set1,set2)) then
	  end do ! do set2 = 1,NumSets
	end do ! do set1=1,NumSets

	return
	end subroutine WriteSubsets

! [10/04/04] Now infer subsets during earlier call to routine BuildGPCoeffMPSGEList,
!  so this routine is no longer called
	subroutine InferAllSubsets

! Local
	type(functionGP), pointer :: CurrentFunctionGP
	type(netputGP), pointer :: CurrentNetputGP
	type(endowmentGP), pointer :: CurrentEndowmentGP
	type(field), pointer :: CurrentDemand
	integer :: NumNetputGPDone, NumEndowmentGPDone
	type(domain), pointer :: IOFieldPriceArg
	type(symbol), pointer :: IOFieldPriceSymbol

! Allocate IsSubsetGP array
	allocate(IsSubsetGP(NumSets,NumSets))
! Initialise it all to false
	IsSubsetGP = .false.

	CurrentFunctionGP => FunctionGPList
	do while(associated(CurrentFunctionGP))

	  if(CurrentFunctionGP%IsProdFunctionGP) then
! Run through the o: and i: lines
	    CurrentNetputGP => CurrentFunctionGP%FirstNetputGP
	    NumNetputGPDone = 0
!	    write(*,*)'InferAllSubsets. Starting NetputGPs'
	    do while(NumNetputGPDone.lt.CurrentFunctionGP%NumIFields+CurrentFunctionGP%NumOFields)
	      IOFieldPriceArg => CurrentNetputGP%netputMPSGE%f%arg
	      IOFieldPriceSymbol => CurrentNetputGP%netputMPSGE%f%ident
! Check arguments against those used when IOFieldPriceName was declared
	      call InferSubsetsGP(IOFieldPriceArg,IOFieldPriceSymbol%arg)
	
	      NumNetputGPDone = NumNetputGPDone + 1
	      CurrentNetputGP => CurrentNetputGP%next
	    end do ! while(NumNetputGPDone.lt.CurrentFunctionGP%NumIFields+CurrentFunctionGP%NumOFields)
	  else if(CurrentFunctionGP%IsDemandFunctionGP) then

	  end if

	  CurrentFunctionGP => CurrentFunctionGP%next
	end do !while(associated(CurrentFunction))

! Run through the functions, working out any implied subsets
	
	end subroutine InferAllSubsets

	subroutine InferSubsetsGP(SubsetArgs, BigSetArgs)
! Input
	type(domain), pointer :: SubsetArgs, BigSetArgs

! May be able to infer that Sets in SubsetArgs must be a subset of the corresponding 
!  set in the arguments of BigSetArgs.
! For example, 
! $sectors
! p(o)
! $prod:y(s)
! o:p(o1) <etc>
! Here can infer that o1 must be a subset of o.

! Local
	integer :: n1,n2,i,ArgNumber, SmallSetNumber, BigSetNumber
	character (len=llst) :: SmallSetName, BigSetName
	type(domain), pointer :: SmallDomain, BigDomain

! Should check that number of sets in SubsetArgs is equal to dimension of BigSetArgs
	n1 = GetArgDim(SubsetArgs)
	n2 = GetArgDim(BigSetArgs)
	if(n1.ne.n2) then
!  Re-initialize 'pre' messages again at start of each function
	  call InitializeMessages('pre',0)
	  call InternalErrorStop('InferSubsetsGP. Mismatch in number of arguments.')
	end if
!	write(*,*)'InferSubsetsGP. n1=', n1 

	SmallDomain => SubsetArgs
	BigDomain => BigSetArgs
	ArgNumber = 1
	do while(ArgNumber.le.n1)
	  SmallSetName = SmallDomain%s%name
	  BigSetName = BigDomain%s%name
!	  write(*,*)'InferSubsetsGP. SmallSetName=',trim(SmallSetName),' BigSetName=', trim(BigSetName) 
	  if(.not.EqualStringsIgnoreCase(SmallSetName, BigSetName)) then
!		SmallSetName must be a subset of BigSetName
	    SmallSetNumber = GetSetNumber(SmallSetName)
	    BigSetNumber = GetSetNumber(BigSetName)
!	    write(*,*)'InferSubsetsGP. SmallSetName=',trim(SmallSetName),'is subset of BigSetName=', trim(BigSetName) 
	    IsSubsetGP(SmallSetNumber,BigSetNumber) = .true.
	  end if

	  ArgNumber = ArgNumber + 1
	  SmallDomain => SmallDomain%next	  
	  BigDomain => BigDomain%next	  
	end do ! while(ArgNumber.le.n1)

	return
	end subroutine InferSubsetsGP

	subroutine SetupGEMPACKNames
! Sets up names for the various GEMPACK Coefficients and Variables
! Runs through all $prod and all $demand blocks
! Does not make any declarations, just sets up names
	type (field), pointer :: fnf, SElastField, TElastField
	logical :: SElastPresent, TElastPresent, OtherFieldsPresent
	logical :: SElastIsConstant, TElastIsConstant
	type (record), pointer :: r
	type (function), pointer :: fnMPSGE
	type (functionGP), pointer :: NewFnGP
	type (netputGP), pointer :: NewNetputGP
	type (taxGP), pointer :: NewTaxGP
	type (nest), pointer :: n
	type (netputlist), pointer :: e
	type (nest), pointer :: inputs, outputs
	type (domain), pointer :: InputsSubDomain
	type (domain), pointer :: TempDomain

! for $prod
	type (GPCoeffVarReal) :: InputPrice, InputQuantity 
	type (GPCoeffVarReal) :: OutputPrice, OutputQuantity 
	type (GPCoeffVarReal) :: ThisProdVar, ThisTopVar
	type (GPCoeffVarReal) :: ThisElasticity
	type (symbol), pointer :: ElasticitySymbol
! for $demand
	type (GPCoeffVarReal) :: EndowQFieldCoeff, EndowQFieldVar  ! relate to level of q: field
	character :: SupplyDemandEndowmentChar
	character (len=128) LinePriceAbbrev 

	type (netputlist), pointer :: CurrentElements
	type (netput), pointer :: CurrentNetPut
	type (field), pointer :: CurrentIOField, CurrentQField, CurrentEndowField
	type (domain), pointer :: CurrentIODomain, CurrentIOSubdomain
	type (taxlist), pointer :: CurrentTaxList, FirstTaxList, CurrentTaxList2
	logical :: AreSomeTaxes, ThisElasticityIsConstant, DomainIsFull
	character :: InputOutputChar  ! 'i' for inputs, 'o' for outputs
	character :: SupplyDemandChar  ! 'd' for inputs, 's' for outputs

	type (endowmentlist), pointer :: CurrentEndowmentList
	type (endowment), pointer :: CurrentEndowment
	type (domain), pointer :: CurrentEndowmentDomain
	type (endowmentGP), pointer :: NewEndowmentGP

	character (len=255) :: FunctionAbbreviation  ! [eg is "y" in "$prod:y(s)"]
	type (domain), pointer :: FunctionDomain     ! [eg is "s" in "$prod:y(s)"]
	character (len=255) :: FunctionString  ! [eg is "$prod:y(s)"]
	logical :: IsProd, IsDemand, IsDField, IsEField

	character (len=255) :: CurrentTaxAgentName, CurrentTaxAgentNameGP, ExtraString
	character (len=255) :: TaxAbbrev, TaxLabelPart

	integer :: kpass, i, NumDuplicates

	integer :: fnindex = 0
	character (len=1024) :: rec
	logical DoThis

	type (domain), pointer :: FoundArgs
	logical :: Found
	character :: FoundUserSystemType

10015   format(1x,a)     ! KP
10017   format(2x,3a)

	write(*,'(1x,a)') 'Calling SetupGEMPACKNames'

	call InitializeMessages('all',0)
	Messages%PostLine(1) = 'This occurred while translating to GEMPACK.'
	Messages%PostLine(2) = 'See the accompanying documentation for more information.'

! Find how many sets there are and build SetGPList
	call BuildSetGPList
!	write(*,*)'Ended BuildSetGPList'

	call WriteSymbolList

! BuildGPCoeffMPSGEList builds a list of all the coefficients occurring simply (that is,
!     not inside expressions) in fields in the MGE file.
! It also infers subsets from the prices etc in the MGE file
!	write(*,*)' Calling BuildGPCoeffMPSGEList'
	call BuildGPCoeffMPSGEList
!	write(*,*)' Ended BuildGPCoeffMPSGEList'

! Temporary - write the list
!	call WriteGPCoeffMPSGEList

	nullify(FunctionGPList)
	nullify(NetputGPList)
	nullify(TaxGPList)
	nullify(EndowmentGPList)
	nullify(GPNameList)
	nullify(GPReadList)
	nullify(GPDeclarationList)
	nullify(ReadHeaderGPList)

	fnMPSGE => functionlist
	do while (associated(fnMPSGE))
	  r => fnMPSGE%firstrecord
	  fnf => r%firstfield

	  IsProd = fnf%label.eq.'$prod'
	  IsDemand = fnf%label.eq.'$demand'

!  Re-initialize 'pre' messages again at start of each function
	  call InitializeMessages('pre',0)
	  Messages%PreLine(1) = 'Processing function '//trim(fnf%label)//':'//trim(fnf%data)

! Echo this function so user sees progress
	  if(EchoMainProgressGP) then
	    write(*,'(2x,a)') trim(Messages%PreLine(1))
	  end if
!

	  FunctionString = trim(fnf%label)//':'//trim(fnf%data)

	  if (IsProd.or.IsDemand) then

!	    write(*,10015) ' ** SetupGEMPACKNames: Next $prod or $demand'
!	    write(*,10017) 'SetupGEMPACKNames: %data: ', trim(fnf%data)
!	    write(*,10017) 'SetupGEMPACKNames: %identtext: ', trim(fnf%identtext)
!	    write(*,10017) 'SetupGEMPACKNames: %argtext: ', trim(fnf%argtext)


! Get the elasticity info
	    call GetElasticityInfo(fnMPSGE, SElastPresent, TElastPresent, &
		SElastField, TElastField, OtherFieldsPresent)

! OtherFieldsPresent tells if are any fields besides s: and t: fields
	    if(OtherFieldsPresent) then

! This means that have nested function. This is not allowed when translating to GEMPACK.
!  When translating to GEMPACK, first need to run a preliminary program to split the
!   nests into separate functions.

	      call ErrorStop( &
		'Nests not allowed here when translating to GEMPACK.'// &
! "\n" means new line
	        '\n First convert MPS file to split nests into separate functions, then process here again.')

	    end if	    

!	    if(SElastPresent) then
!	      write(*,*)'SElast is present'
!	    else
!	      write(*,*)'SElast is not present'
!	    end if
!	    if(TElastPresent) then
!	      write(*,*)'TElast is present'
!	    else
!	      write(*,*)'TElast is not present'
!	    end if

! Put the info about this into a new FunctionGP
	    call newfunctionGP(NewFnGP, fnMPSGE)

	    NewFnGP%IsProdFunctionGP = IsProd
	    NewFnGP%IsDemandFunctionGP = IsDemand

	    NewFnGP%SElastPresent = SElastPresent
	    NewFnGP%TElastPresent = TElastPresent
	    if(SElastPresent) then
	      call ConvertElastToGPCoeffReal('s', FunctionString, &
		    SElastField, ThisElasticity, ThisElasticityIsConstant)
	      NewFnGP%SElasticity = ThisElasticity
	      NewFnGP%SElastIsConstant = ThisElasticityIsConstant
! Add name to GPNameList
! [26/04/04] Only if it not aleady in that list
	      call IsNameInGPNameList(ThisElasticity%name, Found, FoundUserSystemType, FoundArgs)
	      if(.not.Found) then
	        call AddToGPNameList( ThisElasticity%name, 'u', 'c', ThisElasticity%arg)
	      end if
	    end if
	    if(TElastPresent) then
	      call ConvertElastToGPCoeffReal('t', FunctionString, &
		    TElastField, ThisElasticity, ThisElasticityIsConstant)
	      NewFnGP%TElasticity = ThisElasticity
	      NewFnGP%TElastIsConstant = ThisElasticityIsConstant
! Add name to GPNameList
! [26/04/04] Only if it not aleady in that list
	      call IsNameInGPNameList(ThisElasticity%name, Found, FoundUserSystemType, FoundArgs)
	      if(.not.Found) then
	        call AddToGPNameList( ThisElasticity%name, 'u', 'c', ThisElasticity%arg)
	      end if
	    end if

! Initialise Count of number of i: and o: fields associated with this function
	    NewFnGP%NumIFields = 0
	    NewFnGP%NumOFields = 0
! Initialise Count of number of d: and e: fields associated with this function
	    NewFnGP%NumDFields = 0
	    NewFnGP%NumEFields = 0

!	   End "if (IsProd.or.IsDemand) then"
	  end if

	  if (IsProd) then

! Temporary
	    if(.not.associated(fnf%ident)) then
	      write(*,*)'$prod. fnf%identtext=', trim(fnf%identtext)
	      call InternalErrorStop('$prod:'//trim(FunctionAbbreviation)//' fnf%ident is not associated.')
	    end if

! Example
! $prod:y(s)          s:sigma(s)         
!  o:p(s)            q:supply(s)
!  i:pf(f)           q:factor(f,s)

! ??
! (temp)    call WriteRecord(' ** $prod record:', r)

	    FunctionAbbreviation = fnf%identtext  ! [eg is "y" in "$prod:y(s)"]
	    FunctionAbbreviation = trim(FunctionAbbreviation)
	    FunctionDomain => fnf%arg    ! [eg is "s" in "$prod:y(s)"]


! ActivityLevelVar   [eg "y(s) in "$prod:y(s)]
!		  ActivityLevelVar should be in the sectors list, so don't
!			to declare it here (nor to set up labelinfo) 
	    call InitializeGPCoeffVarReal('v', NewFnGP%ActivityLevelVar)
	    NewFnGP%ActivityLevelVar%name = trim(FunctionAbbreviation)
	    NewFnGP%ActivityLevelVar%arg => fnf%arg
	    NewFnGP%ActivityLevelVar%labelinfo = fnf%ident%labelinfo

! TotalRevCoeff
	    call InitializeGPCoeffVarReal('c', NewFnGP%TotalRevCoeff)
	    NewFnGP%TotalRevCoeff%name = ConstructGPName('c', 's', FunctionDomain, &
					'R_'//trim(FunctionAbbreviation), 'MR')
	    call upper(NewFnGP%TotalRevCoeff%name)   ! Convert name to upper case
	    NewFnGP%TotalRevCoeff%arg => FunctionDomain 
	    NewFnGP%TotalRevCoeff%labelinfo = 'Total revenue for '//trim(FunctionString)
! MargRevVar
	    call InitializeGPCoeffVarReal('v', NewFnGP%MargRevVar)
	    NewFnGP%MargRevVar%name = ConstructGPName('v', 's', FunctionDomain, &
						'mr_'//trim(FunctionAbbreviation), 'mr')
	    call lower(NewFnGP%MargRevVar%name)   ! Convert name to lower case
	    NewFnGP%MargRevVar%arg => FunctionDomain 
	    NewFnGP%MargRevVar%labelinfo = '%-change in marginal revenue for '//trim(FunctionString)
! TotalCostCoeff
	    call InitializeGPCoeffVarReal('c', NewFnGP%TotalCostCoeff)
	    NewFnGP%TotalCostCoeff%name = ConstructGPName('c', 's', FunctionDomain, &
					'C_'//trim(FunctionAbbreviation), 'MC')
	    call upper(NewFnGP%TotalCostCoeff%name)   ! Convert name to upper case
	    NewFnGP%TotalCostCoeff%arg => FunctionDomain 
	    NewFnGP%TotalCostCoeff%labelinfo = 'Total cost for '//trim(FunctionString)
! MargCostVar
	    call InitializeGPCoeffVarReal('v', NewFnGP%MargCostVar)
	    NewFnGP%MargCostVar%name = ConstructGPName('v', 's', FunctionDomain, &
						'mc_'//trim(FunctionAbbreviation), 'mc')
	    call lower(NewFnGP%MargCostVar%name)   ! Convert name to lower case
	    NewFnGP%MargCostVar%arg => FunctionDomain 
	    NewFnGP%MargCostVar%labelinfo = '%-change in marginal cost for '//trim(FunctionString)

!		Add this to FunctionGPList 
	    call AddToFunctionGPList( NewFnGP)

! Now go through its O: and I: lines adding coeff and var ($prod)
	    do kpass = 1,2
! Do outputs on pass 1, inputs on pass 2
	      if(kpass.eq.1) then
	        CurrentElements => fnMPSGE%outputs%elements
		InputOutputChar = 'o'
	      else if(kpass.eq.2) then
	        CurrentElements => fnMPSGE%inputs%elements
		InputOutputChar = 'i'
	      end if

!	      write(*,*) ' ** KPASS=', kpass, 'InputOutputChar=', InputOutputChar

! Run through the netputs of this type
	      do while(associated(CurrentElements))
	        CurrentNetput => CurrentElements%np
		CurrentIOField => CurrentNetput%f
		CurrentQField => CurrentNetput%qref
		CurrentIODomain => CurrentNetput%d
		CurrentIOSubdomain => CurrentNetput%sd
		CurrentTaxList => CurrentNetput%t
		AreSomeTaxes = associated(CurrentTaxList)

	        Messages%PreLine(2) = 'Processing line beginning '// &
			InputOutputChar//':'//trim(CurrentIOField%data)
!  Re-initialize 'pre' messages past number 2
	        call InitializeMessages('pre',2)

!		write(*,*) 'CurrentNetput%qref is ', trim(CurrentNetput%qref%label), &
!							':', trim(CurrentNetput%qref%data)
!		if(AreSomeTaxes) then
!		  write(*,*)'Are some taxes here'
!		else
!		  write(*,*)'Are no taxes here'
!		end if

!                   SupplyDemandChar is 's' for output, 'd' for input
	        SupplyDemandChar = ProdSDChar(CurrentNetput%output)

! [09/06/04] At present do not handle exceptions on a:, t:, p:, m: or n: fields in i: or o: lines
		if(associated(CurrentNetput%pref)) then
	          if(CurrentNetput%pref%condtn.ne.' ') then
	            call ErrorStop('Sorry. At present this program cannot handle exceptions on p: fields in o: or i: lines')
		  end if
	        end if

! Increment NumIFields or NumOFields
		if(InputOutputChar.eq.'o') NewFnGP%NumOFields = NewFnGP%NumOFields + 1
		if(InputOutputChar.eq.'i') NewFnGP%NumIFields = NewFnGP%NumIFields + 1

!  Begin a new NetputGP
		allocate(NewNetputGP)
		NewNetputGP%netputMPSGE => CurrentNetput

! i: or o: field
! IOPriceVar should be in the commodities list, so don't
!			to declare it here (nor to set up labelinfo) 
	        call InitializeGPCoeffVarReal('v', NewNetputGP%IOPriceVar)
! NO. [This has already been declared as a $commodity] Use call to ConstructGPName to that this name is added to GPNameList  
! NO.		NewNetputGP%IOPriceVar%name = ConstructGPName('v', 'u', CurrentIOField%arg, &
! NO.		    CurrentIOField%ident%name, ' ')
		newNetputGP%IOPriceVar%name = CurrentIOField%ident%name 
	        call lower(NewNetputGP%IOPriceVar%name)   ! Convert name to lower case
		NewNetputGP%IOPriceVar%arg => CurrentIOField%arg
		NewNetputGP%IOPriceVar%labelinfo = CurrentIOField%ident%labelinfo

! IOPriceCoeff
! [This is declared in the $commodities section]
	        call InitializeGPCoeffVarReal('c', NewNetputGP%IOPriceCoeff)
! [05/06/04] Use function GPLevelsName
!WAS		newNetputGP%IOPriceCoeff%name = trim(CurrentIOField%ident%name)//'_L' 
!WAS	        call upper(NewNetputGP%IOPriceCoeff%name)   ! Convert name to upper case
		newNetputGP%IOPriceCoeff%name = GPLevelsName(CurrentIOField%ident%name) 
		NewNetputGP%IOPriceCoeff%arg => CurrentIOField%arg
		NewNetputGP%IOPriceCoeff%labelinfo = CurrentIOField%ident%labelinfo

! q: field
	        Messages%PreLine(3) = 'Processing "'// &
			trim(CurrentQField%label)//':'//trim(CurrentQField%data)//'"'
!  Re-initialize 'pre' messages past number 3
	        call InitializeMessages('pre',3)

! IOQFieldValueCoeff, IOQFieldQuantityVar, QFieldQuantityCoeffOrRealMPSGE
! [28/03/04] Get these via call to routine GetQFieldValueCoeffEtc

		call GetQFieldValueCoeffEtc( &
! Input
	  	  CurrentQField, &
! CurrentLineField is the field from i:, o: or e: at start of line
! It is CurrentIOField in IO case
	  	  CurrentIOField, & 
! CurrentLineDomain is CurrentNetput%d in IO case
	  	  CurrentNetput%d, &
! FunctionAbbreviation is 
	  	  FunctionAbbreviation, FunctionString, &
! SupplyDemandEndowmentChar is SupplyDemandChar in IO case
! LineChar is InputOutputChar in IO case
	  	  SupplyDemandChar, InputOutputChar, &
! LineHasRField must be false here
		  .false., & 
! Output
 ! QFieldQuantityCoeff is NewNetputGP%QFieldIOQuantiyCoeff in IO case
	  	  newNetputGP%IOQFieldQuantityCoeff, & 
 ! QFieldQuantityVar is NewNetputGP%IOQuantiyVar in IO case
	  	  NewNetputGP%IOQFieldQuantityVar, & 
! QFieldValueCoeff is NewNetputGP%IOQFieldValueCoeff in IO case
	  	  newNetputGP%IOQFieldValueCoeff, &
! QFieldValueVar is NewNetputGP%IOQFieldValueVar in IO case
	  	  newNetputGP%IOQFieldValueVar, &
! QFieldArgGP is NewNetputGP%IOArgGP in IO case (equals QFieldValeCoeff%arg at present)
	  	  NewNetputGP%IOArgGP, &      
 ! QFieldQuantityCoeffOrRealMPSGE is NewNetputGP%IOQFieldQuantityCoeffOrRealMPSGE in IO case
	  	  NewNetputGP%IOQFieldQuantityCoeffOrRealMPSGE, &
		  NewNetputGP%QFieldIsExpression, NewNetputGP%QFieldExpressionString, &
		  NewNetputGP%QFieldNeedGEMPACKCoeff, &
		  LinePriceAbbrev)

!		  if(NewNetputGP%QFieldIsExpression) then
!		    write(*,*) Messages%PreLine(3), 'IsExpression is true'
!		  else
!		    write(*,*) Messages%PreLine(3), 'IsExpression is false'
!		  end if 

! [26/04/04] Process p: field if present
		  if(associated(CurrentNetput%pref)) then
! Set up PFieldIsExpression and PFieldExpressionString
		    call AnalyseField(CurrentNetput%pref, NewNetputGP%PFieldIsExpression, NewNetputGP%PFieldExpressionString)
		  end if

! PFieldCoeff
	          call InitializeGPCoeffVarReal('c', NewNetputGP%PFieldCoeff)
! For example, BTOPYPD for tax on o:pd in $prod:y 
	          NewNetputGP%PFieldCoeff%name = ConstructGPName('c', 's', NewNetputGP%IOArgGP, &
			'BT'//InputOutputChar//'P'//trim(FunctionAbbreviation)//trim(CurrentIOField%ident%name), &
			'BT'//InputOutputChar//'P')
	          call upper(NewNetputGP%PFieldCoeff%name)   ! Convert name to upper case
	          NewNetputGP%PFieldCoeff%arg => NewNetputGP%IOArgGP 
	    	  NewNetputGP%PFieldCoeff%labelinfo = 'Benchmark total power of tax on '// &
			trim(CurrentNetput%qref%label)//':'//trim(CurrentNetput%qref%data)
! For the present, this is a parameter - only look at its benchmark value. [Later should
!   try to update it, I think]
	          NewNetputGP%PFieldCoeff%IsParam = .true.

!  Add this NetputGP to NetputGPList
		call AddToNetputGPList(NewNetputGP)

! If this is the first netputGP associated with this function, set
		if(NewFnGP%NumIFields+NewFnGP%NumOFields.eq.1) then
		  NewFnGP%FirstNetputGP => NewNetputGP
		end if

! Taxes for this netput

		NewNetputGP%NumTaxTypes = 0
! Record FirstTaxList for use in checking duplicate agent names
		FirstTaxList => CurrentNetput%t

		if(AreSomeTaxes.and. .not.associated(CurrentTaxList)) then
		  call InternalErrorStop('AreSomeTaxes problem')
		end if

		do while(associated(CurrentTaxList))
		  NewNetputGP%NumTaxTypes = NewNetputGP%NumTaxTypes + 1

!---------------------------------------------------------------------------------------------------
! [09/06/04] At present do not handle exceptions on a:, t:, m: or n: fields in i: or o: lines
		  if(associated(CurrentTaxlist%a)) then
	            if(CurrentTaxlist%a%condtn.ne.' ') then
	              call ErrorStop('Sorry. At present this program cannot handle exceptions on a: fields in o: or i: lines')
		    end if
	          end if
		  if(associated(CurrentTaxlist%t)) then
	            if(CurrentTaxlist%t%condtn.ne.' ') then
	              call ErrorStop('Sorry. At present this program cannot handle exceptions on t: fields in o: or i: lines')
		    end if
	          end if
		  if(associated(CurrentTaxlist%m)) then
	            if(CurrentTaxlist%m%condtn.ne.' ') then
	              call ErrorStop('Sorry. At present this program cannot handle exceptions on m: fields in o: or i: lines')
		    end if
	          end if
		  if(associated(CurrentTaxlist%n)) then
	            if(CurrentTaxlist%n%condtn.ne.' ') then
	              call ErrorStop('Sorry. At present this program cannot handle exceptions on n: fields in o: or i: lines')
		    end if
	          end if


!OLD At present this GEMPACK conversion cannot handle M: or N: fields in tax stuff
! [28/04/04] Now handle there fields
!OLD		  if(associated(CurrentTaxList%m).or.associated(CurrentTaxList%n)) then
!OLD		    call ErrorStop('Sorry, ths program cannot handle m: or n: tax fields at present.')
!OLD		  end if

! Details of this tax type

! [27/04/04] Now look at p: fields
!OLD For GEMPACK use, can ignore the p: field (CurrentNetput%pref)


! Loop through, processing the pairs of a: and t: fields
!  Use NewTaxGP to hold this info for the current pair
		  allocate(NewTaxGP)
		  NewTaxGP%taxlistMPSGE => CurrentTaxList

! [28/04/04] for m: fields
		  NewTaxGP%HasMField = (associated(CurrentTaxList%m))
! [09/06/04] for n: fields
		  NewTaxGP%HasNField = (associated(CurrentTaxList%n))
! If is m: field, there must be an n: field. But can be n: field without m: field
!  since m:1 is the default if is n: field and no m: field.
! Check this relation
		  if(NewTaxGP%HasMField) then
		    if(.not.NewTaxGP%HasNField) then
		      call InternalErrorStop('Is an m: field here without an n: field')
		    end if
		  end if

! Get agent from a: field. Same agent may be in two or more fields on this line. Add
!  an integer (2,3 etc) to name if so.
		  CurrentTaxAgentName = CurrentTaxList%a%identtext
		  if(NewNetputGP%NumTaxTypes.eq.1) then
		    CurrentTaxAgentNameGP = CurrentTaxAgentName
		  else if(NewNetputGP%NumTaxTypes.gt.1) then
! Go through the earlier ones to see how many times this agent has levied other taxes
		    CurrentTaxList2 => FirstTaxList
		    NumDuplicates = 0	
		    do i=1,NewNetputGP%NumTaxTypes-1
		      if(EqualStringsIgnoreCase(CurrentTaxAgentName, CurrentTaxList2%a%identtext)) then
		        NumDuplicates = NumDuplicates + 1
		      end if
		      if(i.gt.1) then
			CurrentTaxList2 => CurrentTaxList2%next
		      end if
		    end do  ! i
		    if(NumDuplicates.eq.0) then
		      CurrentTaxAgentNameGP = CurrentTaxAgentName
		    else
		      ExtraString = PosintToString(NumDuplicates+1)
		      CurrentTaxAgentNameGP = trim(CurrentTaxAgentName)//ExtraString
		    end if
		  end if

! Details for this tax
!	  type (GPCoeffVarReal) :: TaxPowerCoeff  !! power of tax
!	  type (GPCoeffVarReal) :: TaxRateCoeff  !! rate of tax (number like 0.13)
!	  type (GPCoeffVarReal) :: TaxRevenueCoeff  !! tax revenue
!	  type (GPCoeffVarReal) :: TaxPowerVar  !! %-change in power of tax
!	  type (GPCoeffVarReal) :: TaxRateChangeVar  !! change in tax rate (number like 0.05)
!	  type (GPCoeffVarReal) :: TaxRevenueChangeVar  !! change in tax revenue
! Next will be a real (eg t:0.2) or a Coefficient (eg t:t_p(o))
! [26/04/04] TaxRateCoeffOrRealMPSGE is not set up if TFieldIsExpression is true. Nor if HasMField or HasNField is true,
!	  type (GPCoeffVarReal) :: TaxRateCoeffOrRealMPSGE  !! MPSGE value (initial level) of tax rate
! [26/04/04] Added to handle expressions in t: fields
!	  logical :: TFieldIsExpression  !! Tells if TField is an expression
!	  character (len=512) :: TFieldExpressionString   !! The expression in the t: field (if is such)

! EXAMPLE. Consider line i:pf(f) q: a:gov t:t_pf(f,s) in $prod:va(s)

! TaxAbbrev. eg is "vapfgov" in line i:pf(f) q: a:gov t:t_pf(f,s) in $prod:va(s)
		  TaxAbbrev = trim(FunctionAbbreviation)//trim(CurrentIOField%identtext)//trim(CurrentTaxAgentNameGP)

! TaxLabelPart. eg is "pf for a:gov t:t_pf(f,s) in $prod:va(s)" in line i:pf(f) q: a:gov t:t_pf(f,s) in $prod:va(s)
! [09/06/04] Can be n: field without m: field since m:1 is the default if is n: field and no m: field. So use HasNField here
		  if(.not.NewTaxGP%HasNField) then
		    TaxLabelPart = trim(CurrentIOField%data)//' for "a:'//trim(CurrentTaxAgentName)// &
				   ' t:'//trim(CurrentTaxList%t%data)//'" in '//trim(fnf%label)//':'//trim(fnf%data)
		  else ! if(NewTaxGP%HasNField) then
		   if(NewTaxGP%HasMField) then
		    TaxLabelPart = trim(CurrentIOField%data)//' for "a:'//trim(CurrentTaxAgentName)// &
				   ' m:'//trim(CurrentTaxList%m%data)//'" in '//trim(fnf%label)//':'//trim(fnf%data)
		   else ! if(.not.NewTaxGP%HasMField) then
! Pretend have "m:1"
		    TaxLabelPart = trim(CurrentIOField%data)//' for "a:'//trim(CurrentTaxAgentName)// &
				   ' (implied) m:1" in '//trim(fnf%label)//':'//trim(fnf%data)
		   end if

		  end if
!		  write(*,*)'TaxLabelPart is: ', TaxLabelPart

		  if(.not.NewTaxGP%HasNField) then
! [26/04/04] Set up TFieldIsExpression and TFieldExpressionString
		    call AnalyseField(CurrentTaxList%t, NewTaxGP%TFieldIsExpression, NewTaxGP%TFieldExpressionString)
		  end if

! NewTaxGP%TaxPowerCoeff.  TIPVAPFGOV
	          call InitializeGPCoeffVarReal('c', NewTaxGP%TaxPowerCoeff)
	          NewTaxGP%TaxPowerCoeff%name = ConstructGPName('c', 's', NewNetputGP%IOArgGP, &
			'T'//InputOutputChar//'P'//trim(TaxAbbrev), 'T'//InputOutputChar//'P')
	          call upper(NewTaxGP%TaxPowerCoeff%name)   ! Convert name to upper case
	          NewTaxGP%TaxPowerCoeff%arg => NewNetputGP%IOArgGP 
	    	  NewTaxGP%TaxPowerCoeff%labelinfo = 'Tax power on '//TaxLabelPart

! NewTaxGP%TaxRateCoeff.  TIRVAPFGOV
	          call InitializeGPCoeffVarReal('c', NewTaxGP%TaxRateCoeff)
! Link name to TaxPowerCoeff, just changing 3rd letter "P" to "R"
	          NewTaxGP%TaxRateCoeff%name = ConstructGPName('c', 's', NewNetputGP%IOArgGP, &
			NewTaxGP%TaxPowerCoeff%name(1:2)//'R'//trim(NewTaxGP%TaxPowerCoeff%name(4:)), 'T'//InputOutputChar//'R')
	          call upper(NewTaxGP%TaxRateCoeff%name)   ! Convert name to upper case
	          NewTaxGP%TaxRateCoeff%arg => NewNetputGP%IOArgGP 
	    	  NewTaxGP%TaxRateCoeff%labelinfo = 'Tax rate on '//TaxLabelPart
	    	  NewTaxGP%TaxRateCoeff%IsGE0 = .false.  ! This can be negative

! NewTaxGP%TaxRevenueCoeff.  TIVVAPFGOV
	          call InitializeGPCoeffVarReal('c', NewTaxGP%TaxRevenueCoeff)
! Link name to TaxPowerCoeff, just changing 3rd letter "P" to "V"
	          NewTaxGP%TaxRevenueCoeff%name = ConstructGPName('c', 's', NewNetputGP%IOArgGP, &
			NewTaxGP%TaxPowerCoeff%name(1:2)//'V'//trim(NewTaxGP%TaxPowerCoeff%name(4:)), 'T'//InputOutputChar//'V')
	          call upper(NewTaxGP%TaxRevenueCoeff%name)   ! Convert name to upper case
	          NewTaxGP%TaxRevenueCoeff%arg => NewNetputGP%IOArgGP 
	    	  NewTaxGP%TaxRevenueCoeff%labelinfo = 'Tax revenue on '//TaxLabelPart
	    	  NewTaxGP%TaxRevenueCoeff%IsGE0 = .false.  ! This can be negative

! NewTaxGP%TaxPowerVar.  tivapfgov
	          call InitializeGPCoeffVarReal('v', NewTaxGP%TaxPowerVar)
	          NewTaxGP%TaxPowerVar%name = ConstructGPName('v', 's', NewNetputGP%IOArgGP, &
! Make this name always related to the corresponding coeff. Drop the P which is 3rd letter
		       NewTaxGP%TaxPowerCoeff%name(1:2)//NewTaxGP%TaxPowerCoeff%name(4:), &
		           NewTaxGP%TaxPowerCoeff%name(1:2))
	          call lower(NewTaxGP%TaxPowerVar%name)   ! Convert name to lower case
	          NewTaxGP%TaxPowerVar%arg => NewNetputGP%IOArgGP 
	    	  NewTaxGP%TaxPowerVar%labelinfo = '%-change in power of tax on '//TaxLabelPart
	    	  NewTaxGP%TaxPowerVar%OrigLevel = trim(NewTaxGP%TaxPowerCoeff%name)  

! NewTaxGP%TaxRateChangeVar.  c_tirvapfgov
	          call InitializeGPCoeffVarReal('v', NewTaxGP%TaxRateChangeVar)
	          NewTaxGP%TaxRateChangeVar%name = ConstructGPName('v', 's', NewNetputGP%IOArgGP, &
! Make this name always related to the corresponding coeff. Just add "c_" at the start.
		       "c_"//trim(NewTaxGP%TaxRateCoeff%name), "c_"//trim(NewTaxGP%TaxRateCoeff%name) )
	          call lower(NewTaxGP%TaxRateChangeVar%name)   ! Convert name to lower case
	          NewTaxGP%TaxRateChangeVar%arg => NewNetputGP%IOArgGP 
	    	  NewTaxGP%TaxRateChangeVar%labelinfo = 'Change in rate of tax on '//TaxLabelPart
	    	  NewTaxGP%TaxRateChangeVar%VarType = 'c'
	    	  NewTaxGP%TaxRateChangeVar%OrigLevel = trim(NewTaxGP%TaxRateCoeff%name)  

! NewTaxGP%TaxRevenueChangeVar.  c_tivvapfgov
	          call InitializeGPCoeffVarReal('v', NewTaxGP%TaxRevenueChangeVar)
	          NewTaxGP%TaxRevenueChangeVar%name = ConstructGPName('v', 's', NewNetputGP%IOArgGP, &
! Make this name always related to the corresponding coeff. Just add "c_" at the start.
		       "c_"//trim(NewTaxGP%TaxRevenueCoeff%name), "c_"//trim(NewTaxGP%TaxRevenueCoeff%name) )
	          call lower(NewTaxGP%TaxRevenueChangeVar%name)   ! Convert name to lower case
	          NewTaxGP%TaxRevenueChangeVar%arg => NewNetputGP%IOArgGP 
	    	  NewTaxGP%TaxRevenueChangeVar%labelinfo = 'Change in revenue from tax on '//TaxLabelPart
	    	  NewTaxGP%TaxRevenueChangeVar%VarType = 'c'
	    	  NewTaxGP%TaxRevenueChangeVar%OrigLevel = trim(NewTaxGP%TaxRevenueCoeff%name)  

! [28/04/04] Only do t: field stuff if is a t: field. [If an n: (or m:) field instead, skip this]
		  if(.not.NewTaxGP%HasNField) then
! TaxRateCoeffOrRealMPSGE - what the user gives as the initial value
! [26/04/04] Only if TFieldIsExpression is false
		   if(.not.NewTaxGP%TFieldIsExpression) then
		    if(numeric(CurrentTaxList%t%data)) then
	             call InitializeGPCoeffVarReal('r', NewTaxGP%TaxRateCoeffOrRealMPSGE)
		     NewTaxGP%TaxRateCoeffOrRealMPSGE%name = CurrentTaxList%t%data
		    else
	             call InitializeGPCoeffVarReal('c', NewTaxGP%TaxRateCoeffOrRealMPSGE)
		     NewTaxGP%TaxRateCoeffOrRealMPSGE%name = &
		      ConstructGPName('c', 'u', CurrentTaxList%t%arg, CurrentTaxList%t%ident%name, ' ')
		     NewTaxGP%TaxRateCoeffOrRealMPSGE%arg => CurrentTaxList%t%arg

! labelinfo. This can easily get too long, so drop "value of" if necessary
		     if(LEN_TRIM('Pre-sim value of tax rate on '//trim(TaxLabelPart)).le.73) then
		      NewTaxGP%TaxRateCoeffOrRealMPSGE%labelinfo = 'Pre-sim value of tax rate on '//TaxLabelPart
		     else
		      NewTaxGP%TaxRateCoeffOrRealMPSGE%labelinfo = 'Pre-sim tax rate on '//TaxLabelPart
		     end if
		     NewTaxGP%TaxRateCoeffOrRealMPSGE%IsParam = .true.
		     NewTaxGP%TaxRateCoeffOrRealMPSGE%IsGE0 = .false. ! can be negative
		    end if
		   end if ! if(.not.NewTaxGP%TFieldIsExpression) then
		  end if ! if(.not.NewTaxGP%HasNField) then

		  if(NewNetputGP%NumTaxTypes.ge.2) then
!
! Next only needed if are 2 or more tax types for this netput
!	  type (GPCoeffVarReal) :: TotalTaxPowerCoeff  !! power of tax (all tax types)
!	  type (GPCoeffVarReal) :: TotalTaxPowerVar  !! %-change in power of tax (all tax types)

! TotalTaxPowerCoeff TIP_VA_PF
	            call InitializeGPCoeffVarReal('c', NewNetputGP%TotalTaxPowerCoeff)
	            NewNetputGP%TotalTaxPowerCoeff%name = ConstructGPName('c', 's', NewNetputGP%IOArgGP, &
		      'T'//InputOutputChar//'P_'//trim(FunctionAbbreviation)//'_'//trim(CurrentIOField%ident%name), &
		      'T'//InputOutputChar//'P')
	            call upper(NewNetputGP%TotalTaxPowerCoeff%name)   ! Convert name to upper case
	            NewNetputGP%TotalTaxPowerCoeff%arg => NewNetputGP%IOArgGP 
	    	    NewNetputGP%TotalTaxPowerCoeff%labelinfo = 'Total power of taxes on '// &
		      trim(CurrentIOField%data)//' in '//trim(fnf%label)//':'//trim(fnf%data)

! TotalTaxPowerVar ti_va_pf
	            call InitializeGPCoeffVarReal('v', NewNetputGP%TotalTaxPowerVar)
	            NewNetputGP%TotalTaxPowerVar%name = ConstructGPName('c', 's', NewNetputGP%IOArgGP, &
		      't'//InputOutputChar//'_'//trim(FunctionAbbreviation)//'_'//trim(CurrentIOField%ident%name), &
		      't'//InputOutputChar)
	            call lower(NewNetputGP%TotalTaxPowerVar%name)   ! Convert name to lower case
	            NewNetputGP%TotalTaxPowerVar%arg => NewNetputGP%IOArgGP 
	    	    NewNetputGP%TotalTaxPowerVar%labelinfo = '%-change in total power of taxes on '// &
		      trim(CurrentIOField%data)//' in '//trim(fnf%label)//':'//trim(fnf%data)
	    	    NewNetputGP%TotalTaxPowerVar%OrigLevel = NewNetputGP%TotalTaxPowerCoeff%name

!		   End "if(NewNetputGP%NumTaxTypes.ge.2) then"
		  end if

!-----------------------------------------------------------------------------------
! [28/04/04] for m: and n: field pairs
!	  type (GPCoeffVarReal) :: MFieldCoeffOrRealMPSGE  !! MPSGE value (initial level) of m: field
!	  logical :: MFieldIsExpression  !! Tells if MField is an expression
!	  character (len=512) :: MFieldExpressionString   !! The expression in the m: field (if is such)

! [09/06/04] Can be n: field without m: field since m:1 is the default if is n: field and no m: field. So use HasNField here
!	  type (GPCoeffVarReal) :: NFieldCoeff  !! level of n: variable
!	  type (GPCoeffVarReal) :: NFieldVar  !! change in level of n: variable

		  if(NewTaxGP%HasNField) then

! [09/06/04] Can be n: field without m: field since m:1 is the default if is n: field and no m: field. So use HasNField here
		    if(NewTaxGP%HasMField) then
! Set up MFieldIsExpression and MFieldExpressionString
		      call AnalyseField(CurrentTaxList%m, NewTaxGP%MFieldIsExpression, NewTaxGP%MFieldExpressionString)
		    else ! if(.not.NewTaxGP%HasMField) then
! [09/06/04] Here m:1 applies (is the default). Pretend MFieldIsExpression is false.
		       NewTaxGP%MFieldIsExpression = .false.
		    end if

		    if(.not.NewTaxGP%MFieldIsExpression) then
		     if(.not.NewTaxGP%HasMField) then
! [09/06/04] Here m:1 applies (is the default). Proceed as in the numeric case below.
	              call InitializeGPCoeffVarReal('r', NewTaxGP%MFieldCoeffOrRealMPSGE)
		      NewTaxGP%MFieldCoeffOrRealMPSGE%name = '1'
		     else if(numeric(CurrentTaxList%m%data)) then
	              call InitializeGPCoeffVarReal('r', NewTaxGP%MFieldCoeffOrRealMPSGE)
		      NewTaxGP%MFieldCoeffOrRealMPSGE%name = CurrentTaxList%m%data
		     else
	              call InitializeGPCoeffVarReal('c', NewTaxGP%MFieldCoeffOrRealMPSGE)
		      NewTaxGP%MFieldCoeffOrRealMPSGE%name = &
		        ConstructGPName('c', 'u', CurrentTaxList%m%arg, CurrentTaxList%m%ident%name, ' ')
		      NewTaxGP%MFieldCoeffOrRealMPSGE%arg => CurrentTaxList%m%arg

! labelinfo. This can easily get too long, so drop "value of" if necessary
		      if(LEN_TRIM('Pre-sim value of tax rate on '//trim(TaxLabelPart)).le.73) then
		        NewTaxGP%MFieldCoeffOrRealMPSGE%labelinfo = 'Pre-sim value of tax rate on '//TaxLabelPart
		      else
		        NewTaxGP%MFieldCoeffOrRealMPSGE%labelinfo = 'Pre-sim tax rate on '//TaxLabelPart
		      end if
		      NewTaxGP%MFieldCoeffOrRealMPSGE%IsParam = .true.
		      NewTaxGP%MFieldCoeffOrRealMPSGE%IsGE0 = .false. ! can be negative
		     end if
		    end if ! if(.not.NewTaxGP%MFieldIsExpression) then

! Actual rate (at any stage) is NFieldCoeff*MFieldCoeff when HasMField or HasNField is true
!	  type (GPCoeffVarReal) :: MFieldCoeff  !! Levels variable, initialised at m: field value, can be shocked
!	  type (GPCoeffVarReal) :: MFieldVar  !! Linear change variable, the change in MFieldCoeff
! NewTaxGP%MFieldCoeff.  TIMVAPFGOV
	            call InitializeGPCoeffVarReal('c', NewTaxGP%MFieldCoeff)
! Link name to TaxRateCoeff, just changing 3rd letter "R" to "M"
	            NewTaxGP%MFieldCoeff%name = ConstructGPName('c', 's', NewNetputGP%IOArgGP, &
			NewTaxGP%TaxRateCoeff%name(1:2)//'M'//trim(NewTaxGP%TaxRateCoeff%name(4:)), 'T'//InputOutputChar//'M')
	            call upper(NewTaxGP%MFieldCoeff%name)   ! Convert name to upper case
	            NewTaxGP%MFieldCoeff%arg => NewNetputGP%IOArgGP 
	    	    NewTaxGP%MFieldCoeff%labelinfo = 'm: field in '//TaxLabelPart
	    	    NewTaxGP%MFieldCoeff%IsGE0 = .false.  ! This can be negative
! NewTaxGP%MFieldVar.  c_TIMVAPFGOV
	            call InitializeGPCoeffVarReal('v', NewTaxGP%MFieldVar)
	            NewTaxGP%MFieldVar%name = ConstructGPName('v', 's', NewTaxGP%taxlistMPSGE%n%arg, &
					'c_'//NewTaxGP%MFieldCoeff%name, ' ')
	            call lower(NewTaxGP%MFieldVar%name)   ! Convert name to lower case
	            NewTaxGP%MFieldVar%arg => NewTaxGP%MFieldCoeff%arg 
	            NewTaxGP%MFieldVar%VarType = 'c'   ! is a change variable
	            NewTaxGP%MFieldVar%labelinfo = 'Change in '//NewTaxGP%MFieldCoeff%labelinfo

! n: field
		    if(associated(CurrentTaxList%n)) then

! NFieldCoeff
	              call InitializeGPCoeffVarReal('c', NewTaxGP%NFieldCoeff)
	              NewTaxGP%NFieldCoeff%name = ConstructGPName('c', 'u', NewTaxGP%taxlistMPSGE%n%arg, &
					NewTaxGP%taxlistMPSGE%n%identtext, ' ')
	              call upper(NewTaxGP%NFieldCoeff%name)   ! Convert name to upper case
	              NewTaxGP%NFieldCoeff%arg => NewTaxGP%taxlistMPSGE%n%arg 
	              NewTaxGP%NFieldCoeff%labelinfo = 'Endogenous multiplier in '//trim(TaxLabelPart)

	              call InitializeGPCoeffVarReal('v', NewTaxGP%NFieldVar)
	              NewTaxGP%NFieldVar%name = ConstructGPName('v', 'u', NewTaxGP%taxlistMPSGE%n%arg, &
					'c_'//NewTaxGP%taxlistMPSGE%n%identtext, ' ')
	              call lower(NewTaxGP%NFieldVar%name)   ! Convert name to lower case
	              NewTaxGP%NFieldVar%arg => NewTaxGP%taxlistMPSGE%n%arg 
	              NewTaxGP%NFieldVar%VarType = 'c'   ! is a change variable
	              NewTaxGP%NFieldVar%labelinfo = 'Change in endogenous multiplier in '//trim(TaxLabelPart)

		    else ! if(.not.associated(CurrentTaxList%n)) then
		      call InternalErrorStop('Expect n: field when HasNField is true')
		    end if

		  end if ! if(NewTaxGP%HasNField) then
!-----------------------------------------------------------------------------------

! Set NewNetputGP%FirstTaxGP for the current NetputGP
		  if(NewNetputGP%NumTaxTypes.eq.1) then
		    NewNetputGP%FirstTaxGP => NewTaxGP
		  end if

! Add this TaxGP to TaxGPList
		  call AddToTaxGPList(NewTaxGP)

		  CurrentTaxList => CurrentTaxList%next 
		end do  ! while(associated(CurrentTaxList))

		if(NewNetputGP%NumTaxTypes.gt.0) then

!		  write(*,*)'NumTaxtypes for '//InputOutputChar//':'//trim(CurrentIOField%data)//' is ',NewNetputGP%NumTaxTypes 
!
! Next only needed if are one or more taxing agents
!	  type (GPCoeffVarReal) :: IOPriceIncTaxesVar    !! %-change in price including taxes
! Next only needed for outputs when are one or more taxing agents. 
!	  type (GPCoeffVarReal) :: IOQFieldValueVar    !! %-change in value of input or output

! Leave these until now so can use TotalTaxPowerCoeff in OrigLevels below.

! IOPriceIncTaxesVar
! Example. Consider  o:p(o) q:supply(s,o) + taxes in $prod:y(s). 
!   Then IOQFieldQuantityVar%name is p_vs_y_p(s,o) and so we want IOPriceIncTaxesVar%name to be p_ps_y_p(s,o).  
	          call InitializeGPCoeffVarReal('v', NewNetputGP%IOPriceIncTaxesVar)
! Base name on that for IOQFieldValueVar - just change "v" in position 3 to "p"
		  NewNetputGP%IOPriceIncTaxesVar%name = ConstructGPName('v', 's', NewNetputGP%IOArgGP, &
		    'p_p'//trim(NewNetputGp%IOQFieldValueVar%name(4:)), 'p_p'//trim(NewNetputGp%IOQFieldQuantityVar%name(4:)))
		  NewNetputGP%IOPriceIncTaxesVar%arg => NewNetputGP%IOArgGP 
		  NewNetputGP%IOPriceIncTaxesVar%labelinfo = & 
		    '%-change in price inc taxes for '//InputOutputChar//':'//&
		    trim(CurrentIOField%data)//' in '//trim(FunctionString)
	          call lower(NewNetputGP%IOPriceIncTaxesVar%name)   ! Convert name to lower case
		  if(NewNetputGP%NumTaxTypes.eq.1) then
		    NewNetputGP%IOPriceIncTaxesVar%OrigLevel = NewNetputGP%FirstTaxGP%TaxPowerCoeff%name
		  else if(NewNetputGP%NumTaxTypes.ge.2) then
		    NewNetputGP%IOPriceIncTaxesVar%OrigLevel = NewNetputGP%TotalTaxPowerCoeff%name
		  end if  


! [06/04/04] IOQFieldValueVar is now set up in call to GetQFieldValueCoeff so does not need to be done here.
! IOQFieldValueVar (includes taxes in o: field, does not include taxes in i: field)
! Example. Consider  o:p(o) q:supply(s,o) + taxes in $prod:y(s). Then IOQFieldValueVar%name is vs_y_p(s,o)  
!EARLIER	            call InitializeGPCoeffVarReal('v', NewNetputGP%IOQFieldValueVar)
! Base name on that for IOQFieldQuantityVar - just change "q" at start to "v"
!EARLIER		    NewNetputGP%IOQFieldValueVar%name = ConstructGPName('v', 's', NewNetputGP%IOArgGP, &
!EARLIER		      'v'//trim(NewNetputGp%IOQFieldQuantityVar%name(2:)), 'v'//trim(NewNetputGp%IOQFieldQuantityVar%name(2:)))
!EARLIER		    NewNetputGP%IOQFieldValueVar%arg => NewNetputGP%IOArgGP 
!EARLIER		    NewNetputGP%IOQFieldValueVar%labelinfo = & 
!EARLIER		      '%-change in value inc taxes for '//InputOutputChar//':'//&
!EARLIER		      trim(CurrentIOField%data)//' in '//trim(FunctionString)
!EARLIER	            call lower(NewNetputGP%IOQFieldValueVar%name)   ! Convert name to lower case
!EARLIER		    NewNetputGP%IOQFieldValueVar%OrigLevel = NewNetputGP%IOQFieldValueCoeff%name  


!		 End "if(NewNetputGP%NumTaxTypes.gt.0) then"
		end if



		CurrentElements => CurrentElements%next
	      end do

	    end do ! kpass loop

!	   End "if (IsProd) then"
	  else if (IsDemand) then

! (temp)    call WriteRecord(' ** $demand record:', r)

	    FunctionAbbreviation = fnf%identtext  ! [eg is "y" in "$prod:y(s)"]
	    FunctionAbbreviation = trim(FunctionAbbreviation)
	    FunctionDomain => fnf%arg    ! [eg is "s" in "$prod:y(s)"]
!	    write(*,*)'$demand. FunctionAbbreviation is: ', trim(FunctionAbbreviation)
	    if(.not.associated(fnf%ident)) then
	      write(*,*)'$demand. fnf%identtext=', trim(fnf%identtext)
	      write(*,*) '$demand:'//trim(FunctionAbbreviation)//' fnf%ident is not associated. Should stop.'
!??	      call InternalErrorStop('$demand:'//trim(FunctionAbbreviation)//' fnf%ident is not associated.')
	    end if

! [09/06/04] At present do not handle exceptions on a demand block
	    if(fnf%condtn.ne.' ') then
	      call ErrorStop('Sorry. At present this program cannot handle exceptions on $demand: blocks')
	    end if

! Example
! $demand:ra
!  d:pc              q:cons
!  e:pf(f)           q:endow(f)

! IncomeVar   [eg "ra" in "$demand:ra"]
!		  IncomeVar should be in the sectors list, so don't
!			to declare it here (nor to set up labelinfo) 
	    call InitializeGPCoeffVarReal('v', NewFnGP%IncomeVar)
	    NewFnGP%IncomeVar%name = trim(FunctionAbbreviation)
	    NewFnGP%IncomeVar%arg => fnf%arg
	    NewFnGP%IncomeVar%labelinfo = fnf%ident%labelinfo

! I think that there must always be exactly one d: field
	    NewFnGP%NumDFields = 1



! TotalIncomeCoeff
!	  type (GPCoeffVarReal) :: TotalIncomeCoeff !! Total income for this consumer
		! Is equal to total value of endowments (summed over all e: lines) plus total tax income
! One for each $demand function
! The value of this is the sum over ALL e: fields.
! The %-change in this is just IncomeVar. So this could be a levels variable.

! [05/06/04] Want to make sure that the levels variable associated with any $consumer,
!  namely TotalIncomeCoeff, is of the form "VI_" followed by the name of the $consumer as declared in MGE file.
!   That is why length of $consumer as declared is limited to llcs-3 characters - see the test elsewhere in this code.

	    call InitializeGPCoeffVarReal('c', NewFnGP%TotalIncomeCoeff)
! [05/06/04] Use function GPLevelsName
!WAS	    NewFnGP%TotalIncomeCoeff%name = ConstructGPName('c', 's', FunctionDomain, &
!WAS					'VI_'//trim(FunctionAbbreviation), 'VI')
	    NewFnGP%TotalIncomeCoeff%name = ConstructGPName('c', 's', FunctionDomain, &
					GPLevelsName(FunctionAbbreviation), 'VI')
	    call upper(NewFnGP%TotalIncomeCoeff%name)   ! Convert name to upper case
	    NewFnGP%TotalIncomeCoeff%arg => FunctionDomain 
	    NewFnGP%TotalIncomeCoeff%labelinfo = 'Total value of income for consumer in '//trim(FunctionString)
 


! Other things
! for each e: line, have EndowQFieldQuantityVar eg qs_ra_pf

! In any $demand: block, is just one equation and it is a natural levels equation.
! It says TotalIncomeCoeff = SUM value from q: fields, summed across all e: lines
!                                        PLUS the sum of all revenue accruing to the agent (look in $prod: blocks)

! Note that the prices in $commodities are MARKET prices !!

! Will have linear eq linking %-change in values in q: fields with the price in e: field and the
!   EndowQFieldQuantityVar  


!		Add this to FunctionGPList 
	    call AddToFunctionGPList( NewFnGP)

	    CurrentEndowmentList => fnMPSGE%endowments

! Run through the endowments in this list
	    do while(associated(CurrentEndowmentList))
	        CurrentEndowment => CurrentEndowmentList%e
		CurrentQField => CurrentEndowment%q
		CurrentEndowmentDomain => CurrentEndowment%d
	        CurrentEndowField => CurrentEndowment%f

	        NewFnGP%NumEFields = NewFnGP%NumEFields + 1

	        Messages%PreLine(2) = 'Processing line beginning '// &
			'e:'//trim(CurrentEndowField%data)
!  Re-initialize 'pre' messages past number 2
	        call InitializeMessages('pre',2)

! [09/06/04] At present do not handle exceptions on e: fields or on q: fields in e: lines
	        if(CurrentEndowField%condtn.ne.' '.or.CurrentQField%condtn.ne.' ') then
	          call ErrorStop('Sorry. At present this program cannot handle exceptions on e: fields or on q: fields in e: lines')
	        end if

! [09/06/04] At present do not handle exceptions on r: fields in e: lines
		if(associated(CurrentEndowment%r)) then
	          if(CurrentEndowment%r%condtn.ne.' ') then
	            call ErrorStop('Sorry. At present this program cannot handle exceptions on r: fields in e: lines')
		  end if
	        end if

!  Begin a new EndowmentGP
		allocate(NewEndowmentGP)
		NewEndowmentGP%endowmentMPSGE => CurrentEndowment

	        Messages%PreLine(2) = 'Processing line beginning '// &
			'e:'//trim(CurrentEndowField%data)
!  Re-initialize 'pre' messages past number 2
	        call InitializeMessages('pre',2)

!	type endowmentGP
! Additions to Tom Rutherford's type endowment. These additions needed for GEMPACK
! This is actually a list of endowmentGP's
!	  type(endowment), pointer :: endowmentMPSGE !! Pointer to the MPSGE endowment

! EndowArgGP is analagous to IOArgGP
! At present, EndowArgGP and EndowQFieldValueCoeff%arg are always the same. But use EndowArgGP in the code
!  in case this changes in some special cases which are excluded at present.
!	  type (domain), pointer :: EndowArgGP  

! The next 4 are analagous to the corresponding IO things in a netputGP
!	  type (GPCoeffVarReal) :: EndowQFieldQuantityVar  !! %-change in quantity of each endowment  
!	  type (GPCoeffVarReal) :: EndowPriceVar    !! %-change in price (The price after e: at start of line)
!	  type (GPCoeffVarReal) :: EndowQFieldValueCoeff  !! value (level) of endowment
!	  type (GPCoeffVarReal) :: EndowQFieldValueVar  !! %-change in value (level) of endowment
! Next will be a real (eg q:200) or a Coefficient (eg q:totfac)
!	  type (GPCoeffVarReal) :: EndowQFieldQuantityCoeffOrRealMPSGE  !! MPSGE value (initial level) of endowment

!	  type(endowmentGP), pointer :: next    !! Pointer to next in linked list of all endowmentGPs
!	end type endowmentGP

! EndowPriceVar is price after e: at start of this e: line
!		  EndowPriceVar should be in the commodities list, so don't need
!			to declare it here (nor to set up labelinfo) 
	        call InitializeGPCoeffVarReal('v', NewEndowmentGP%EndowPriceVar)
		NewEndowmentGP%EndowPriceVar%name = CurrentEndowField%ident%name 
	        call lower(NewEndowmentGP%EndowPriceVar%name)   ! Convert name to lower case
		NewEndowmentGP%EndowPriceVar%arg => CurrentEndowField%arg
		NewEndowmentGP%EndowPriceVar%labelinfo = CurrentEndowField%ident%labelinfo

! EndowPriceCoeff - levels version of price after e: at start of this e: line
!		  EndowPriceCoeff is also declared in the $commodities section so don't need
!			to declare it here (nor to set up labelinfo) 
	        call InitializeGPCoeffVarReal('c', NewEndowmentGP%EndowPriceCoeff)
! [05/06/04] Use function GPLevelsName
!WAS		NewEndowmentGP%EndowPriceCoeff%name = trim(CurrentEndowField%ident%name)//'_L' 
!WAS	        call upper(NewEndowmentGP%EndowPriceCoeff%name)   ! Convert name to upper case
		NewEndowmentGP%EndowPriceCoeff%name = GPLevelsName(CurrentEndowField%ident%name) 
		NewEndowmentGP%EndowPriceCoeff%arg => CurrentEndowField%arg
		NewEndowmentGP%EndowPriceCoeff%labelinfo = CurrentEndowField%ident%labelinfo

! q: field
	        Messages%PreLine(3) = 'Processing "'// &
			trim(CurrentQField%label)//':'//trim(CurrentQField%data)//'"'
!  Re-initialize 'pre' messages past number 3
	        call InitializeMessages('pre',3)

! EndowQFieldValueCoeff, EndowQFieldQuantityVar, EndowQFieldQuantityCoeffOrRealMPSGE
! [28/03/04] Get these via call to routine GetQFieldValueCoeffEtc

! Is there an r: field
		NewEndowmentGP%HasRField = (associated(NewEndowmentGP%EndowmentMPSGE%r))

		SupplyDemandEndowmentChar = 's'

		call GetQFieldValueCoeffEtc( &
! Input
	  	  CurrentQField, &
! CurrentLineField is the field from i:, o: or e: at start of line
! It is CurrentIOField in IO case
	  	  CurrentEndowField, & 
! CurrentLineDomain is CurrentNetput%d in IO case
	  	  CurrentEndowmentDomain, &
! FunctionAbbreviation is variable name after $prod: or $demand: [eg is "y" in "$prod:y(s)"]
! FunctionString is $prod: or $demand: followed by variable plus arguments [eg is "$prod:y(s)"]
! These are already set up in this case 
	  	  FunctionAbbreviation, FunctionString, &
! SupplyDemandEndowmentChar is SupplyDemandChar in IO case
! LineChar is InputOutputChar in IO case
! call	  	  SupplyDemandEndowmentChar, LineChar, & 
	  	  SupplyDemandEndowmentChar, 'e', & 
! LineHasRField (in the call)
		  NewEndowmentGP%HasRField, &
! Output
! EndowQFieldCoeff is either EndowQFieldQuantityCoeff or EndowUnrationedQuantityCoeff
	  	  EndowQFieldCoeff, &
! EndowQFieldVar is either EndowQFieldQuantityVar or EndowUnrationedQuantityVar
	  	  EndowQFieldVar, & 
! QFieldValueCoeff is NewNetputGP%IOQFieldValueCoeff in IO case
	  	  NewEndowmentGP%EndowQFieldValueCoeff, &
! QFieldValueVar is NewNetputGP%IOQFieldValueVar in IO case
	  	  NewEndowmentGP%EndowQFieldValueVar, &
! QFieldArgGP is NewNetputGP%IOArgGP in IO case (equals QFieldValeCoeff%arg at present)
	  	  NewEndowmentGP%EndowArgGP, &      
! QuantityVar is NewNetputGP%IOQFieldQuantityVar in IO case
! QFieldQuantityCoeffOrRealMPSGE is NewNetputGP%IOQFieldQuantityCoeffOrRealMPSGE in IO case
	  	  NewEndowmentGP%EndowQFieldQuantityCoeffOrRealMPSGE, &
		  NewEndowmentGP%QFieldIsExpression, NewEndowmentGP%QFieldExpressionString, &
		  NewEndowmentGP%QFieldNeedGEMPACKCoeff, &
		  LinePriceAbbrev)

!		  if(NewNetputGP%QFieldIsExpression) then
!		    write(*,*) Messages%PreLine(3), 'IsExpression is true'
!		  else
!		    write(*,*) Messages%PreLine(3), 'IsExpression is false'
!		  end if 

		if(NewEndowmentGP%HasRField) then
! Q: field is unrationed quantity
	          NewEndowmentGP%EndowUnrationedQuantityCoeff = EndowQFieldCoeff
	          NewEndowmentGP%EndowUnrationedQuantityVar = EndowQFieldVar
!		  write(*,*)'EndowUnrationedQuantityCoeff%name is ', NewEndowmentGP%EndowUnrationedQuantityCoeff%name
!		  write(*,*)'EndowUnrationedQuantityVar%name is ', NewEndowmentGP%EndowUnrationedQuantityVar%name

! Need to add EndowQFieldQuantityCoeff and EndowQFieldQuantityVar
	          call InitializeGPCoeffVarReal('c', NewEndowmentGP%EndowQFieldQuantityCoeff)
! Always attempt to use the full system name here
	          NewEndowmentGP%EndowQFieldQuantityCoeff%name = ConstructGPName('c', 's', EndowQFieldCoeff%arg, &
! Add "Q" at start
		    'Q'//SupplyDemandEndowmentChar//'_'//trim(FunctionAbbreviation)// &
		    '_'//trim(LinePriceAbbrev), 'Q'//SupplyDemandEndowmentChar)
	          call upper(NewEndowmentGP%EndowQFieldQuantityCoeff%name)   ! Convert name to upper case
	          NewEndowmentGP%EndowQFieldQuantityCoeff%arg => EndowQFieldCoeff%arg 
	          NewEndowmentGP%EndowQFieldQuantityCoeff%labelinfo = 'Actual quantity in e:'// &
			trim(CurrentEndowField%data)//' in '//trim(FunctionString)
	          NewEndowmentGP%EndowQFieldQuantityCoeff%IsGE0 = .false.   ! quantity may be negative here

	          call InitializeGPCoeffVarReal('v', NewEndowmentGP%EndowQFieldQuantityVar)
	          NewEndowmentGP%EndowQFieldQuantityVar%name = ConstructGPName('v', 's', EndowQFieldCoeff%arg, &
					'c_'//NewEndowmentGP%EndowQFieldQuantityCoeff%name, ' ')
	          call lower(NewEndowmentGP%EndowQFieldQuantityVar%name)   ! Convert name to lower case
	          NewEndowmentGP%EndowQFieldQuantityVar%arg => EndowQFieldCoeff%arg 
	          NewEndowmentGP%EndowQFieldQuantityVar%VarType = 'c'   ! is a change variable
	          NewEndowmentGP%EndowQFieldQuantityVar%labelinfo = 'Change in actual quantity in e:'// &
			trim(CurrentEndowField%data)//' in '//trim(FunctionString)

		else
! Q: field is the actual quantity
	          NewEndowmentGP%EndowQFieldQuantityCoeff = EndowQFieldCoeff
		  NewEndowmentGP%EndowQFieldQuantityVar = EndowQFieldVar
		end if
   
		if(NewEndowmentGP%HasRField) then
! In this case, have the levels equation EndowQFieldQuantityCoeff = EndowUnrationedQuantityCoeff * EndowRFieldCoeff 
		end if

! [06/04/04] EndowQFieldValueVar is now set up in call to GetQFieldValueCoeffEtc so do not need to redo it here
! EndowQFieldValueVar
! Example. Consider  o:p(o) q:supply(s,o) + taxes in $prod:y(s). Then IOQFieldValueVar%name is vs_y_p(s,o)  
!EARLIER	        call InitializeGPCoeffVarReal('v', NewEndowmentGP%EndowQFieldValueVar)
! Base name on that for EndowQFieldQuantityVar - just change "q" at start to "v"
!EARLIER		NewEndowmentGP%EndowQFieldValueVar%name = ConstructGPName('v', 's', NewEndowmentGP%EndowArgGP, &
!EARLIER		      'v'//trim(NewEndowmentGP%EndowQFieldQuantityVar%name(2:)), 'v'//trim(NewEndowmentGP%EndowQFieldQuantityVar%name(2:)))
!EARLIER		NewEndowmentGP%EndowQFieldValueVar%arg => NewEndowmentGP%EndowArgGP 
!EARLIER		NewEndowmentGP%EndowQFieldValueVar%labelinfo = & 
!EARLIER		      '%-change in value of e:'//&
!EARLIER		      trim(CurrentEndowField%data)//' in '//trim(FunctionString)
!EARLIER	        call lower(NewEndowmentGP%EndowQFieldValueVar%name)   ! Convert name to lower case
!EARLIER		NewEndowmentGP%EndowQFieldValueVar%OrigLevel = NewEndowmentGP%EndowQFieldValueCoeff%name

! EndowRFieldCoeff and EndowRFieldVar
		if(NewEndowmentGP%HasRField) then
	          call InitializeGPCoeffVarReal('c', NewEndowmentGP%EndowRFieldCoeff)
	          NewEndowmentGP%EndowRFieldCoeff%name = ConstructGPName('c', 'u', NewEndowmentGP%EndowmentMPSGE%r%arg, &
					NewEndowmentGP%EndowmentMPSGE%r%identtext, ' ')
	          call upper(NewEndowmentGP%EndowRFieldCoeff%name)   ! Convert name to upper case
	          NewEndowmentGP%EndowRFieldCoeff%arg => NewEndowmentGP%EndowmentMPSGE%r%arg 
	          NewEndowmentGP%EndowRFieldCoeff%labelinfo = 'Rationing quantity in e:'// &
			trim(CurrentEndowField%data)//' in '//trim(FunctionString)

	          call InitializeGPCoeffVarReal('v', NewEndowmentGP%EndowRFieldVar)
	          NewEndowmentGP%EndowRFieldVar%name = ConstructGPName('v', 'u', NewEndowmentGP%EndowmentMPSGE%r%arg, &
					'c_'//NewEndowmentGP%EndowmentMPSGE%r%identtext, ' ')
	          call lower(NewEndowmentGP%EndowRFieldVar%name)   ! Convert name to lower case
	          NewEndowmentGP%EndowRFieldVar%arg => NewEndowmentGP%EndowmentMPSGE%r%arg 
	          NewEndowmentGP%EndowRFieldVar%VarType = 'c'   ! is a change variable
	          NewEndowmentGP%EndowRFieldVar%labelinfo = 'Change in rationing quantity in e:'// &
			trim(CurrentEndowField%data)//' in '//trim(FunctionString)
		end if

!  Add this EndowmentGP to EndowmentGPList
		call AddToEndowmentGPList(NewEndowmentGP)

! If this is the first endowmentGP associated with this function, set
		if(NewFnGP%NumEFields.eq.1) then
		  NewFnGP%FirstEndowmentGP => NewEndowmentGP
		end if


	        CurrentEndowmentList => CurrentEndowmentList%next
	    end do 

!	   End "if (IsProd) then..else if(IsDemand) then.."
	  end if

	  fnMPSGE => fnMPSGE%next
	end do

! Leave WalrasSlackVar until routine DoMarketClearingEquations

! Write details about FunctionGPList and GPNameList

!	call WriteFunctionGPList
!	call WriteGPNameList

! Infer any subsets - must wait until FunctionGPList is set up to do this
! [10/04/04] Now infer subsets during earlier call to routine BuildGPCoeffMPSGEList
!NO	call InferAllSubsets
!	write(*,*)'Ended InferAllSubsets'

	
	write(*,*)'Ended SetupGEMPACKNames'

	return
	end subroutine SetupGEMPACKNames

	subroutine WriteGPNameList

	type (GPName), pointer :: ThisGPName

	write(*,*)' Begin WriteGPNameList'

	ThisGPName => GPNameList
	do while(associated(ThisGPName))

	  write(*,*) 'WriteGPNameList: ThisGPName%name is ', trim(ThisGPName%name)
	  write(*,*) 'WriteGPNameList: Type of this is ', ThisGPName%type, ' ExogEndogStatus is ', ThisGPName%ExogEndogStatus

	  ThisGPName => ThisGPName%next
	end do

	write(*,*)' End WriteGPNameList'

	return
	end subroutine WriteGPNameList

	subroutine WriteFunctionGPList

! Writes some details about everything in FunctionGPList

	type (functionGP), pointer :: fnGP

	write(*,*)' Begin WriteFunctionGPList'

	fnGP => FunctionGPList
	do while(associated(fnGP))

	  if(fnGP%IsProdFunctionGP) then
	    write(*,*) 'TotalRevCoeffName is ', fnGP%TotalRevCoeff%name
	  else if(fnGP%IsDemandFunctionGP) then
	    write(*,*) 'TotalIncomeCoeff is ', fnGP%TotalIncomeCoeff%name
	  end if

	  fnGP => fnGP%next
	end do

	write(*,*)' End WriteFunctionGPList'

	return
	end subroutine WriteFunctionGPList

!!	Allocate a new functionGP pointer with default values

	subroutine newfunctionGP(fnGP, fnMPSGE)
! Input
	type (function), pointer ::fnMPSGE
! Output
	type (functionGP), pointer :: fnGP

	nullify(fnGP)
	allocate(fnGP)
	fnGP%functionMPSGE => fnMPSGE
	return
	end subroutine newfunctionGP

	subroutine ConvertToGP

	type (functionGP), pointer :: fnGP
	type (function), pointer :: fnMPSGE
	type (field), pointer :: fnf, NetputIODEField
	type (symbol), pointer :: ThisSymbol
	type (GPCoeffVarReal) :: ImpliedVariable, ImpliedLevelsVariable
	integer :: kpass, NumNetputGPDone, NumEndowmentGPDone
	type (netputGP), pointer :: CurrentNetputGP  
	type (taxGP), pointer :: CurrentTaxGP  

!  Does declarations for $prod
!  Based on Tom Rutherford's routine "declarations"
	type (record), pointer :: r
	type (nest), pointer :: n
	type (netputlist), pointer :: e
	type (nest), pointer :: inputs, outputs
	type (domain), pointer :: InputsSubDomain
! for $prod
	type (GPCoeffVarReal) :: InputPrice, InputQuantity 
	type (GPCoeffVarReal) :: OutputPrice, OutputQuantity 
	type (GPCoeffVarReal) :: ThisProdVar, ThisTopVar
	type (GPCoeffVarReal) :: ThisElasticity
	type (symbol), pointer :: ElasticitySymbol
! for $demand
	type (endowmentlist), pointer :: CurrentEndowmentList
	type (endowmentGP), pointer :: CurrentEndowmentGP
	type (GPCoeffVarReal) :: DemandPrice, DemandQuantity 
	type (GPCoeffVarReal) :: EndowmentPrice, EndowmentQuantity
	type (GPCoeffVarReal) :: ThisDemandVar
	logical :: DFieldExists, EFieldExists, Found 

	integer :: CurrentTaxNumber
	integer :: fnindex = 0
	character (len=1024) :: rec, ThisExpression
	logical :: DoThis
	type (GPCoeffMPSGE), pointer :: GPCoeffMPSGEHere

	character (len=512) :: StatementStart, OutputString, OutputStringAlls
	character (len=512) :: TempString1

	type (domain), pointer :: FoundArgs
	character :: FoundUserSystemType

	logical :: FoundInConstraint  ! [03/06/04]


10015   format(1x,a)     ! KP
10017   format(2x,3a)

	write(*,fmt)'Beginning routine ConvertToGP'

! Whether to translate to a mixed or a linear TAB file
!  Only one of these will be true
!	logical :: MixedTABFile, LinearTABFile
	MixedTABFile = .true.
	LinearTABFile = .false.

	NumGPReads = 0  ! Instant count of number of Read statements

! Common declarations
!	write(*,*)'Calling StartTABGP'
	call StartTABGP
!	write(*,*)'Ended StartTABGP'

! Initialize Preline message strings. [Leave the PostLine ones saying are converting to GP.]
	call InitializeMessages('pre',0)

	write(*,fmt)' Processing sectors, commodities, consumers and auxiliary variables'

! Run through the sectors, commodities and consumers declaring these as variables
	do kpass=1,4
! Do sectors when KPASS=1
! Do commidities when KPASS=2
! Do consumers when KPASS=3
! [26/04/04] Do auxiliary variables when KPASS=4
	  if(kpass.eq.1) then
	    write(iotabgp, '(/,A)') '! $sectors: !'
	    write(iotabgp, '(A)') '!  [The variables below are %-changes in the activity level of these sectors.] !'
	    Messages%PreLine(1) = 'Processing $sectors'
	  else if(kpass.eq.2) then
	    write(iotabgp, '(/,A)') '! $commodities: !'
	    write(iotabgp, '(A)') '!  [These are market prices] !'
	    Messages%PreLine(1) = 'Processing $commodities'
	  else if(kpass.eq.3) then
	    write(iotabgp, '(/,A)') '! $consumers: !'
	    write(iotabgp, '(A)') '!  [The variables below are %-changes in the income of these consumers.] !'
! Don't need to add ORIG_LEVEL for $consumers since later will declare levels
!  variable (total value of income for the relevant $consumer) which is associated with each $consumer   
	    Messages%PreLine(1) = 'Processing $consumers'
	  else if(kpass.eq.4) then
	    write(iotabgp, '(/,A)') '! $auxiliary: !'
	    write(iotabgp, '(A)') '!  [The auxiliary variables. Linear version is a change variable.] !'
	    Messages%PreLine(1) = 'Processing $auxiliary'
	  end if
!  Re-initialize 'pre' messages past number 1
	  call InitializeMessages('pre',1)
 
	  ThisSymbol => idlist    ! idlist contains all symbols
	  do while(associated(ThisSymbol))
	    DoThis = .false.
	    if(kpass.eq.1) DoThis = ThisSymbol%type.eq.'sector'
	    if(kpass.eq.2) DoThis = ThisSymbol%type.eq.'commodity'
	    if(kpass.eq.3) DoThis = ThisSymbol%type.eq.'consumer'
	    if(kpass.eq.4) DoThis = ThisSymbol%type.eq.'auxiliary'

	    Messages%PreLine(2) = 'Processing '//trim(ThisSymbol%name)
	    call InitializeMessages('pre',2)

! [09/06/04] At present do not handle domain restrictions in the declaration of a consumer or an auxiliary variable
	    if(DoThis.and.(kpass.eq.3.or.kpass.eq.4)) then
	     if(ThisSymbol%lines%line%record%firstfield%condtn.ne.' ') then
	      if(kpass.eq.3) then
	        call ErrorStop('Sorry. At present this program cannot handle domain restrictions in the $consumers: section')
	      else if(kpass.eq.4) then
	        call ErrorStop('Sorry. At present this program cannot handle domain restrictions in the $auxiliary: section')
	      end if
	     end if
	    end if ! if(kpass.eq.3.or.kpass.eq.4) then

! Sectors, Commodities and Consumers
	    if(DoThis.and.kpass.le.3) then

! Declare this as a variable - use ImpliedVariable to hold info
	      call InitializeGPCoeffVarReal('v', ImpliedVariable)
!	      write(*,*) 'ConvertToGP. ThisSymbol%name is:', trim(ThisSymbol%name)	      
	      ImpliedVariable%name = ThisSymbol%name
	      ImpliedVariable%arg => ThisSymbol%arg
	      ImpliedVariable%labelinfo = trim(ThisSymbol%labelinfo)//' (%-change)'

!NO	      if(kpass.eq.1) then
! [26/04/04] No ORIG_LEVEL for $sectors any more since are now declaring a levels
!   variable and saying initial value of activity is 1.
!NO Orig_Level for $sectors. Find this in a $prod: function
!NO  [The orig_level value for these is the sum of the values in the q: fields, summed over all o: lines.
!NO    Indeed, the orig_level is coeffficient R_ (TotalRevCoeff).] 

!NO		fnGP => FunctionGPList
!NO		Found = .false.
!NO		do while(associated(fnGP).and. (.not.Found))
!NO		  if(fnGP%IsProdFunctionGP) then
!NO		    if(EqualStringsIgnoreCase(ThisSymbol%name, fnGP%ActivityLevelVar%name)) then
!NO		      Found = .true.
!NO		      ImpliedVariable%OrigLevel = fnGP%TotalRevCoeff%name
! [18/04/04] With the "new" MPSGE syntax rules (see the note about this at the top of this file),
!  this is the only $prod: block this variable can occur in.
!  And the sets over which the variable is declared in the $sectors part must be equal to the sets
!   at the start of this $prod: block.
!  It removes problems with ORIG_LEVEL if declare the variable over the sets at the top of the $prod: block.
! [This will be appropriate even if allow $ in declaration blocks (eg y(s)$y0(s))
!  So change ImpliedVariable%arg accordingly.
!NO	      	      ImpliedVariable%arg => fnGP%TotalRevCoeff%arg
!NO		    end if
!NO		  end if
!NO		  fnGP => fnGP%next
!NO		end do ! do while(associated(fnGP).and. (.not.Found))
!NO		if(.not.Found) then
!NO		  call InternalErrorStop('Did not find '//trim(ThisSymbol%name)//' amongst $prod: blocks.')
!NO		end if
!NO	      end if ! if(kpass.eq.1) then

! Omit Orig_Level now that also declare levels variables - instead add Formula(Initial)s for
!  the levels variables - see below
! NO	      if(kpass.eq.2) then
!		  Assume all prices are 1 initially
! NO	        ImpliedVariable%OrigLevel = '1.0'
! NO	      end if

	      if(kpass.eq.3) then
! Find this variable in its $demand block.
		fnGP => FunctionGPList
		Found = .false.
		do while(associated(fnGP).and. (.not.Found))
		  if(fnGP%IsDemandFunctionGP) then
		    if(EqualStringsIgnoreCase(ThisSymbol%name, fnGP%IncomeVar%name)) then
		      Found = .true.
! [18/04/04] With the "new" MPSGE syntax rules (see the note about this at the top of this file),
!  this is the only $prod: block this variable can occur in.
!  And the sets over which the variable is declared in the $sectors part must be equal to the sets
!   at the start of this $prod: block.
!  It removes problems with ORIG_LEVEL if declare the variable over the sets at the top of the $prod: block.
! [This will be appropriate even if allow $ in declaration blocks (eg y(s)$y0(s))
!  So change ImpliedVariable%arg accordingly.
	      	      ImpliedVariable%arg => fnGP%TotalIncomeCoeff%arg
		    end if
		  end if
		  fnGP => fnGP%next
		end do ! do while(associated(fnGP).and. (.not.Found))
		if(.not.Found) then
		  call InternalErrorStop('Did not find '//trim(ThisSymbol%name)//' amongst $demand: blocks.')
		end if

! [05/06/04] Check that name is not too long. Want to make sure that the associated levels variable,
!  namely TotalIncomeCoeff, is of the form "VI_" followed by the name of the $consumer as declared in MGE file.
!  Hence "+3" in the test below.
		if(LEN_TRIM(ThisSymbol%name)+3.ge.llcs) then
		  Call ErrorStop('Sorry, when translating to GEMPACK,'//&
				'\n  names of $consumers are limited to '// &
				trim(PosintToString(llcs-3))//' characters.')		
		end if ! if(LEN_TRIM(ThisSymbol%name)+2.ge.llcs) then

	      end if ! if(kpass.eq.3) then

	      call DeclareGPCoeffVar(ImpliedVariable)
! Also add this name to GPNameList
	      call AddToGPNameList( ImpliedVariable%name, 'u', 'v', ImpliedVariable%arg)

! [26/04/04] Ditto for $sectors - kpass=1. Initial value of activity can be set equal
!  to 1 - there is no real scale for activity level so can noramlize it to equal
!   1 at the start
	      if(kpass.eq.1.or.kpass.eq.2) then

! Check that name is not too long
		if(LEN_TRIM(ThisSymbol%name)+2.ge.llcs) then
		  Call ErrorStop('Sorry, when translating to GEMPACK,'//&
				'\n  names of $sectors and of $commodities are limited to '// &
				trim(PosintToString(llcs-2))//' characters.')		
		end if ! if(LEN_TRIM(ThisSymbol%name)+2.ge.llcs) then

! Also declare levels values of prices for commodities
	        call InitializeGPCoeffVarReal('c', ImpliedLevelsVariable)
! [05/06/04] Use function GPLevelsName
!WAS	        ImpliedLevelsVariable%name = trim(ThisSymbol%name)//'_L'
	        ImpliedLevelsVariable%name = GPLevelsName(ThisSymbol%name)
	        ImpliedLevelsVariable%arg => ThisSymbol%arg
	        ImpliedLevelsVariable%labelinfo = trim(ThisSymbol%labelinfo)//' (levels value)'
		call DeclareGPLevelsVar(ImpliedLevelsVariable, ImpliedVariable)
! Also add this name to GPNameList
	        call AddToGPNameList( ImpliedLevelsVariable%name, 'u', 'c', ImpliedLevelsVariable%arg)

! And give Formula(Initial) for its original value
		StatementStart = 'Formula (Initial)'
		call ArgToAllsGP(ImpliedLevelsVariable%arg, OutputStringAlls)
! Write this line
		OutputString = trim(StatementStart)//' '//trim(OutputStringAlls)
	        call WriteOneLineToTAB(OutputString)
! LHS, "=" and 1.0
		call CoeffVarRealToGP(ImpliedLevelsVariable, TempString1)
		OutputString = trim(TempString1)//' = '//'1.0 ;' 
! Write this line
	        call WriteOneLineToTAB('   '//OutputString)

	      end if ! if(kpass.eq.1.or.kpass.eq.2) then

!	     End "if(DoThis.and.kpass.le.3) then"
	    else if(DoThis.and.kpass.eq.4) then
! Declare auxiliary as levels variable, associated linear var is a change var

! [03/06/04] Check that this auxiliary variable appears after $constraint: somewhere in the file
!  Ideally I think that this checking should be in MPSGE.F90
! If not found, is fatal error, so do not have to check result "FoundInConstraint".
	      call CheckAuxiliaryIsInConstraint( ThisSymbol%name, FoundInConstraint)

! Declare this as a Coefficient - use ImpliedLevelsVariable to hold info
	      call InitializeGPCoeffVarReal('c', ImpliedLevelsVariable)
!	      write(*,*) 'ConvertToGP. ThisSymbol%name is:', trim(ThisSymbol%name)	      
	      ImpliedLevelsVariable%name = ThisSymbol%name
	      ImpliedLevelsVariable%arg => ThisSymbol%arg
	      ImpliedlevelsVariable%labelinfo = trim(ThisSymbol%labelinfo)
! Linear variable is this name with "c_" in front
	      call InitializeGPCoeffVarReal('v', ImpliedVariable)
	      ImpliedVariable%name = 'c_'//trim(ThisSymbol%name)
	      ImpliedVariable%arg => ThisSymbol%arg
	      ImpliedVariable%labelinfo = 'change in '//trim(ThisSymbol%labelinfo)
	      call DeclareGPLevelsVar(ImpliedLevelsVariable, ImpliedVariable)

! [26/04/04] Also add these names to GPNameList if not already there. [But they probably are
!   there since were added when declared EndowRFieldCoeff and EndowRFieldVar 
	      call IsNameInGPNameList(ImpliedLevelsVariable%name, Found, FoundUserSystemType, FoundArgs)
	      if(.not.Found) then
	        call AddToGPNameList( ImpliedLevelsVariable%name, 'u', 'c', ImpliedLevelsVariable%arg)
	      end if
	      call IsNameInGPNameList(ImpliedVariable%name, Found, FoundUserSystemType, FoundArgs)
	      if(.not.Found) then
	        call AddToGPNameList( ImpliedVariable%name, 'u', 'v', ImpliedVariable%arg)
	      end if

	    end if ! else if(DoThis.and.kpass.eq.4) then

	    ThisSymbol => ThisSymbol%next
	  end do
	end do ! kpass

!	write(*,*)'Ended sectors etc'	

! Do two passes when writing TAB file
! On the first pass, just declare and read values of GEMPACK coefficient with
!  names taken directly from the MGE file. Set GPCoeffMPSGEPass true on this pass.
! On the second pass, declare all other coefficients and do the rest of the
!  TAB file - that is, all the formulas, equations, assertions etc. Set
!  GPCoeffMPSGEPass false on this pass.
! To do this, loop over BigCoeffPass=1,2. Set GPCoeffMPSGEPass true/false when BigCoeffPass=1/2 respectively.

      do BigCoeffPass=1,2
	GPCoeffMPSGEPass = (BigCoeffPass.eq.1)

	if(GPCoeffMPSGEPass) then
! Put heading on TAB file for section declaring and reading coeffs appearing in the MGE file
	  call WriteOneLineToTAB(' ')
	  call WriteOneLineToTAB('! Declaration and Reads of some Coefficients used in the MGE file !')
	end if ! if(GPCoeffMPSGEPass) then

	fnGP => FunctionGPList
	do while (associated(fnGP))
	  fnMPSGE => fnGP%functionMPSGE
	  fnf => fnMPSGE%firstrecord%firstfield
	  if ((fnf%label.eq.'$prod').or.(fnf%label.eq.'$demand')) then

	    Messages%PreLine(1) = 'Processing function '//trim(fnf%label)//':'//trim(fnf%data)
!  Re-initialize 'pre' messages past number 1
	    call InitializeMessages('pre',1)

! Echo this function so user sees progress (will echo each block twice, when BigCoeffPass=1 and 2
	    if(EchoMainProgressGP) then
	      write(*,'(2x,a)') trim(Messages%PreLine(1))
	    end if

! Put out comment above the declarations for this function (just echos the MPS text)
! Only do this when GPCoeffMPSGEPass is false
	    if(.not.GPCoeffMPSGEPass) then
!	      write(*,*)'Calling OutputMPSFunctionAsGPComment'
	      call OutputMPSFunctionAsGPComment(fnMPSGE)
!	      write(*,*)'Called OutputMPSFunctionAsGPComment'
	    end if

	  end if

	  if (fnf%label.eq.'$prod') then

! Declare any elasticities associated with this function
!	    write(*,*)'Starting S elasticity'
	    if(fnGP%SElastPresent) then
	      if(.not.fnGP%SElastIsConstant) then
	        call DeclareGPCoeffVar(fnGP%SElasticity)
	      end if
	    end if
!	    write(*,*)'Starting T elasticity'
	    if(fnGP%TElastPresent) then
	      if(.not.fnGP%TElastIsConstant) then
	        call DeclareGPCoeffVar(fnGP%TElasticity)
	      end if
	    end if

!	    write(*,*)'Done elasticities'

! Declarations for:
!	  type (GPCoeffVarReal) :: TotalRevCoeff !! Marginal revenue as coefficient (relates to outputs)
!	  type (GPCoeffVarReal) :: MargRevVar !! Marginal revenue as variable (relates to outputs)
!	  type (GPCoeffVarReal) :: TotalCostCoeff !! Marginal cost as coefficient (relates to inputs)
!	  type (GPCoeffVarReal) :: MargCostVar !! Marginal cost as variable (relates to inputs)
	    call DeclareGPCoeffVar(fnGP%TotalRevCoeff)
	    call DeclareGPCoeffVar(fnGP%TotalCostCoeff)
	    call DeclareGPCoeffVar(fnGP%MargRevVar)
	    call DeclareGPCoeffVar(fnGP%MargCostVar)

!	    write(*,*)'Declared to point 1'

! Declarations for each i: field and each o: field
!		 Set CurrentNetputGP to point to first i: or o: field associated with
!		   this function
	    CurrentNetputGP => fnGP%FirstNetputGP
	    NumNetputGPDone = 0
	    do while(NumNetputGPDone.lt.fnGP%NumIFields+fnGP%NumOFields)

	      if(.not.(associated(CurrentNetputGP))) then
		call InternalErrorStop( &
		  'CurrentNetputGP is not associated. NumNetputGPDone while in routine ConvertToGP')
	      end if


	      NetputIODEField => CurrentNetputGP%NetputMPSGE%f   ! This is the :, o:, d: or e: field at start of this netput
	      Messages%PreLine(2) = 'Processing line beginning '// &
	      				trim(NetputIODEField%label)//':'//trim(NetputIODEField%data)
!  Re-initialize 'pre' messages past number 2
	      call InitializeMessages('pre',2)
!	      write(*,*) trim(Messages%PreLine(2))

!	      if(CurrentNetputGP%QFieldIsExpression) then
!		write(*,*) trim(Messages%PreLine(2)), 'QFieldIsExpression is true'
!	      else
!		write(*,*) trim(Messages%PreLine(2)), 'QFieldIsExpression is false'
!	      end if 


! Do declarations for:
!	  type (GPCoeffVarReal) :: IOQFieldQuantityVar  !! %-change in input or output quantity
!	  type (GPCoeffVarReal) :: IOPriceVar    !! %-change in price
!	  type (GPCoeffVarReal) :: IOQFieldValueCoeff  !! value (level) of input or output
!	  type (GPCoeffVarReal) :: IOQFieldQuantityCoeffOrRealMPSGE  !! MPSGE quantity (initial level) of input or output

! Do not declare IOPriceVar since it should have been declared under $commodities
! NO	      call DeclareGPCoeffVar(CurrentNetputGP%IOPriceVar)

! If writing mixed TAB file, IOQFieldValueCoeff is a levels variable if are any
!   tax terms on this line
! Now always levels if MixedTABFile
!WAS	      if(MixedTABFile.and.CurrentNetputGP%NumTaxTypes.gt.0) then
	      if(MixedTABFile) then
	        call DeclareGPLevelsVar(CurrentNetputGP%IOQFieldValueCoeff, CurrentNetputGP%IOQFieldValueVar)
	      else
	        call DeclareGPCoeffVar(CurrentNetputGP%IOQFieldValueCoeff)
	      end if

! Next seems to be wrong
! NO. IOQFieldQuantityVar is not a new declaration if there is no subdomain
! NO.	      if(associated(CurrentNetputGP%NetputMPSGE%sd)) then

! Is the ORIG_LEVEL in the next variable correct?
!NO??	        write(iotabgp, '(a)') ' ! ?? Is the ORIG_LEVEL in next variable correct ?? !'

! IOQFieldQuantityVar is now always associated with IOQuantityCoeff which is a levels variable
! WAS	        call DeclareGPCoeffVar(CurrentNetputGP%IOQFieldQuantityVar)
	      if(MixedTABFile) then
	        call DeclareGPLevelsVar(CurrentNetputGP%IOQFieldQuantityCoeff, CurrentNetputGP%IOQFieldQuantityVar)
	      else
	        call DeclareGPCoeffVar(CurrentNetputGP%IOQFieldQuantityCoeff)
	      end if

! NO.	      else
! Should be able to add ORIG_LEVEL to the quantity associated with the $prod.
! NO.	        write(iotabgp, '(a)') ' ! ?? Should associate ORIG_LEVEL with the activity variable in this $prod ?? !'
! NO.	      end if

! IOQFieldQuantityCoeffOrRealMPSGE - not set up if CurrentNetputGP%QFieldIsExpression is true
	      if(.not.CurrentNetputGP%QFieldIsExpression) then
!  Nothing to declare if this is a real
	       if(CurrentNetputGP%IOQFieldQuantityCoeffOrRealMPSGE%type.eq.'c') then
! Only declare it if it is different from IOQFieldValueCoeff (the one updated in GEMPACK)
	        if(trim(CurrentNetputGP%IOQFieldQuantityCoeffOrRealMPSGE%name).ne. &
	               trim(CurrentNetputGP%IOQFieldQuantityCoeff%name)) then
	          call DeclareGPCoeffVar(CurrentNetputGP%IOQFieldQuantityCoeffOrRealMPSGE)
	        end if
	       end if
	      else if(CurrentNetputGP%QFieldIsExpression) then
! Now only do this when GPCoeffMPSGEPass is false. [When GPCoeffMPSGEPass is true, declare them if they
!  occur outside an expression, when they may be levels variables. By calling DeclareAllInThisGPCoeffMPSGEList
!  only when GPCoeffPass is false, only declare them as Coefficient(Parameter)s if they do not occur
!   outside an expression.]
	        if(.not.GPCoeffMPSGEPass) then
! Get the GPCoeffMPSGEs into GPCoeffMPSGEHere
	          ThisExpression = ExpressionToGPSyntax(CurrentNetputGP%QFieldExpressionString, GPCoeffMPSGEHere)
! Declare all things in GPCoeffMPSGEHere (which are not already declared)
		  call DeclareAllInThisGPCoeffMPSGEList(GPCoeffMPSGEHere)
	        end if ! if(.notGPCoeffMPSGEPass) then
	
	      end if


	      if(CurrentNetputGP%NumTaxTypes.gt.0) then

!-------------------------------------------------------------------------------------
! [26/04/04] p: field
! PFieldCoeff - only present if are taxes?
	        call DeclareGPCoeffVar(CurrentNetputGP%PFieldCoeff)

		if(associated(CurrentNetputGP%netputMPSGE%pref)) then
! Only do this when GPCoeffMPSGEPass is false. [When GPCoeffMPSGEPass is true, declare them if they
!  occur outside an expression, when they may be levels variables. By calling DeclareAllInThisGPCoeffMPSGEList
!  only when GPCoeffPass is false, only declare them as Coefficient(Parameter)s if they do not occur
!   outside an expression.]
	          if(.not.GPCoeffMPSGEPass) then
! Get the GPCoeffMPSGEs into GPCoeffMPSGEHere
	            ThisExpression = ExpressionToGPSyntax(CurrentNetputGP%PFieldExpressionString, GPCoeffMPSGEHere)
! Declare all things in GPCoeffMPSGEHere (which are not already declared)
		    call DeclareAllInThisGPCoeffMPSGEList(GPCoeffMPSGEHere)
	          end if ! if(.notGPCoeffMPSGEPass) then
		end if ! if(associated(CurrentNetputGP%netputMPSGE%pref)) then
!-------------------------------------------------------------------------------------

! Run through the taxes
		CurrentTaxGP => CurrentNetputGP%FirstTaxGP
		CurrentTaxNumber = 0
		do while(CurrentTaxNumber.lt.CurrentNetputGP%NumTaxTypes)

	          Messages%PreLine(3) = 'Processing tax with agent '//'a:'// &
	      				trim(CurrentTaxGP%taxlistMPSGE%a%data)
!  Re-initialize 'pre' messages past number 3
	          call InitializeMessages('pre',3)
!	          write(*,*) trim(Messages%PreLine(2))

! Do declarations for:
!	  type (GPCoeffVarReal) :: TaxPowerCoeff  !! power of tax
!	  type (GPCoeffVarReal) :: TaxRateCoeff  !! rate of tax (number like 0.13)
!	  type (GPCoeffVarReal) :: TaxRevenueCoeff  !! tax revenue
!	  type (GPCoeffVarReal) :: TaxPowerVar  !! %-change in power of tax
!	  type (GPCoeffVarReal) :: TaxRateChangeVar  !! change in tax rate (number like 0.05)
!	  type (GPCoeffVarReal) :: TaxRevenueChangeVar  !! change in tax revenue
! Next will be a real (eg t:0.2) or a Coefficient (eg t:t_p(o))
! [26/04/04] TaxRateCoeffOrRealMPSGE is not set up if TFieldIsExpression is true
!	  type (GPCoeffVarReal) :: TaxRateCoeffOrRealMPSGE  !! MPSGE value (initial level) of tax rate

		  if(MixedTABFile) then
! Levels variables
	            call DeclareGPLevelsVar(CurrentTaxGP%TaxPowerCoeff, CurrentTaxGP%TaxPowerVar)
	            call DeclareGPLevelsVar(CurrentTaxGP%TaxRateCoeff, CurrentTaxGP%TaxRateChangeVar)
	            call DeclareGPLevelsVar(CurrentTaxGP%TaxRevenueCoeff, CurrentTaxGP%TaxRevenueChangeVar)
		  else
	            call DeclareGPCoeffVar(CurrentTaxGP%TaxPowerCoeff)
	            call DeclareGPCoeffVar(CurrentTaxGP%TaxRateCoeff)
	            call DeclareGPCoeffVar(CurrentTaxGP%TaxRevenueCoeff)
	            call DeclareGPCoeffVar(CurrentTaxGP%TaxPowerVar)
	            call DeclareGPCoeffVar(CurrentTaxGP%TaxRateChangeVar)
	            call DeclareGPCoeffVar(CurrentTaxGP%TaxRevenueChangeVar)
		  end if

! [28/04/04] Only do t: field stuff if is a t: field. [If an m: or n: field instead, skip this]
		  if(.not.CurrentTaxGP%HasNField) then
! TaxRateCoeffOrRealMPSGE
! [26/04/04] TaxRateCoeffOrRealMPSGE is not set up if TFieldIsExpression is true
		   if(.not.CurrentTaxGP%TFieldIsExpression) then
!  Nothing to declare if this is a real
	            if(CurrentTaxGP%TaxRateCoeffOrRealMPSGE%type.eq.'c') then
	              call DeclareGPCoeffVar(CurrentTaxGP%TaxRateCoeffOrRealMPSGE)
		    end if
		   else if(CurrentTaxGP%TFieldIsExpression) then
! [26/04/04] When t: field is expression, follow the same strategy as for q: fields which are expressions.
! Only do this when GPCoeffMPSGEPass is false. [When GPCoeffMPSGEPass is true, declare them if they
!  occur outside an expression, when they may be levels variables. By calling DeclareAllInThisGPCoeffMPSGEList
!  only when GPCoeffPass is false, only declare them as Coefficient(Parameter)s if they do not occur
!   outside an expression.]
	            if(.not.GPCoeffMPSGEPass) then
! Get the GPCoeffMPSGEs into GPCoeffMPSGEHere
	              ThisExpression = ExpressionToGPSyntax(CurrentTaxGP%TFieldExpressionString, GPCoeffMPSGEHere)
! Declare all things in GPCoeffMPSGEHere (which are not already declared)
		      call DeclareAllInThisGPCoeffMPSGEList(GPCoeffMPSGEHere)
	            end if ! if(.notGPCoeffMPSGEPass) then
		   end if ! else if(CurrentTaxGP%TFieldIsExpression) then
		  end if ! if(.not.CurrentTaxGP%HasNField) then

!----------------------------------------------------------------------------------
! [28/04/04] For m: and n: fields
		  if(CurrentTaxGP%HasNField) then

		    if(MixedTABFile) then
! [08/06/04] The same m: may be in several lines. So only declare it if it has not
!		 already been declared.
	              if (.not.HasBeenDeclaredGP('cs',CurrentTaxGP%MFieldCoeff%name)) then
	                call DeclareGPLevelsVar(CurrentTaxGP%MFieldCoeff, CurrentTaxGP%MFieldVar)
		      end if
! [08/06/04] The same n: field can be in several lines. So only declare it if it has not
!		 already been declared.
	              if (.not.HasBeenDeclaredGP('cs',CurrentTaxGP%NFieldCoeff%name)) then
	                call DeclareGPLevelsVar(CurrentTaxGP%NFieldCoeff, CurrentTaxGP%NFieldVar)
		      end if
		    end if ! if(MixedTABFile) then

! TaxRateCoeffOrRealMPSGE
! [26/04/04] TaxRateCoeffOrRealMPSGE is not set up if MFieldIsExpression is true
		    if(.not.CurrentTaxGP%MFieldIsExpression) then
!  Nothing to declare if this is a real
	              if(CurrentTaxGP%MFieldCoeffOrRealMPSGE%type.eq.'c') then
	                call DeclareGPCoeffVar(CurrentTaxGP%MFieldCoeffOrRealMPSGE)
		      end if
		    else if(CurrentTaxGP%MFieldIsExpression) then
!  When m: field is expression, follow the same strategy as for q: fields which are expressions.
! Only do this when GPCoeffMPSGEPass is false. [When GPCoeffMPSGEPass is true, declare them if they
!  occur outside an expression, when they may be levels variables. By calling DeclareAllInThisGPCoeffMPSGEList
!  only when GPCoeffPass is false, only declare them as Coefficient(Parameter)s if they do not occur
!   outside an expression.]
	             if(.not.GPCoeffMPSGEPass) then
! Get the GPCoeffMPSGEs into GPCoeffMPSGEHere
	              ThisExpression = ExpressionToGPSyntax(CurrentTaxGP%MFieldExpressionString, GPCoeffMPSGEHere)
! Declare all things in GPCoeffMPSGEHere (which are not already declared)
		      call DeclareAllInThisGPCoeffMPSGEList(GPCoeffMPSGEHere)
	             end if ! if(.notGPCoeffMPSGEPass) then
		    end if ! else if(CurrentTaxGP%MFieldIsExpression) then

		  end if ! if(CurrentTaxGP%HasNField) then
!----------------------------------------------------------------------------------

		  CurrentTaxNumber = CurrentTaxNumber + 1
		  CurrentTaxGP => CurrentTaxGP%next
		end do ! while

	        if(CurrentNetputGP%NumTaxTypes.ge.2) then

! Next only needed if are 2 or more tax types for this netput
!	  type (GPCoeffVarReal) :: TotalTaxPowerCoeff  !! power of tax (all tax types)
!	  type (GPCoeffVarReal) :: TotalTaxPowerVar  !! %-change in power of tax (all tax types)

		  if(MixedTABFile) then
! Levels variable
	            call DeclareGPLevelsVar(CurrentNetputGP%TotalTaxPowerCoeff, CurrentNetputGP%TotalTaxPowerVar)
		  else
	            call DeclareGPCoeffVar(CurrentNetputGP%TotalTaxPowerCoeff)
	            call DeclareGPCoeffVar(CurrentNetputGP%TotalTaxPowerVar)
		  end if

!	         End "if(CurrentNetputGP%NumTaxTypes.ge.2) then"
	        end if

!	  integer :: NumTaxTypes
! Next only needed if are one or more taxing agents
!	  type (GPCoeffVarReal) :: IOPriceIncTaxesVar    !! %-change in price including taxes
! Next only needed for outputs when are one or more taxing agents. 
!	  type (GPCoeffVarReal) :: IOQFieldValueVar    !! %-change in value of input or output

!NO??	        write(iotabgp, '(a)') ' ! ?? Is the ORIG_LEVEL in next variable correct ?? !'
	        call DeclareGPCoeffVar(CurrentNetputGP%IOPriceIncTaxesVar)

! If writing a mixed TAB file, this is part of a levels variable already declared
			
		if(LinearTABFile.and.CurrentNetputGP%NetputMPSGE%f%label.eq.'o') then
!NO??	          write(iotabgp, '(a)') ' ! ?? Is the ORIG_LEVEL in next variable correct ?? !'
	          call DeclareGPCoeffVar(CurrentNetputGP%IOQFieldValueVar)
		end if

!	       End "if(CurrentNetputGP%NumTaxTypes.gt.0) then"
	      end if
	      
! Increment NumNetputGPDone
	      NumNetputGPDone = NumNetputGPDone + 1

! Go on to the next netput for this function
	      CurrentNetputGP => CurrentNetputGP%next

!	     End "do while(NumNetputGPDone.lt.fnGP%NumIFields+fnGP%NumOFields)"
	    end do

!	   End "if (fnf%label.eq.'$prod') then"
	  else if(fnf%label.eq.'$demand') then

! Declarations for:
!	  type (GPCoeffVarReal) :: IncomeCoeff !! total income for this agent

	    if(MixedTABFile) then
! Levels variable
	      call DeclareGPLevelsVar(fnGP%TotalIncomeCoeff, FnGP%IncomeVar)
	    else
	      call DeclareGPCoeffVar(FnGP%TotalIncomeCoeff)
	    end if
! Don't declare IncomeVar since it has been declared in $consumers block


	    if(fnGP%NumEFields.gt.0) then

! Declarations for each e: field
!		 Set CurrentEndowmentGP to point to first e: field associated with
!		   this function
	      CurrentEndowmentGP => fnGP%FirstEndowmentGP
	      NumEndowmentGPDone = 0
	      do while(NumEndowmentGPDone.lt.fnGP%NumEFields)

	        Messages%PreLine(2) = 'Processing line beginning '// &
	      				'e:'//trim(CurrentEndowmentGP%endowmentMPSGE%f%data)
!  Re-initialize 'pre' messages past number 2
	        call InitializeMessages('pre',2)
!	        write(*,*) trim(Messages%PreLine(2))

!	        if(CurrentEndowmentGP%QFieldIsExpression) then
!		  write(*,*) trim(Messages%PreLine(2)), 'QFieldIsExpression is true'
!	        else
!		  write(*,*) trim(Messages%PreLine(2)), 'QFieldIsExpression is false'
!	        end if 
! Declarations for:
!	  type (GPCoeffVarReal) :: EndowQFieldQuantityCoeff  !! quantity (level) of each endowment q: field  
!	  type (GPCoeffVarReal) :: EndowQFieldQuantityVar  !! change in quantity of each endowment (q: field) 
!	  type (GPCoeffVarReal) :: EndowQFieldValueCoeff  !! value (level) of endowment
!	  type (GPCoeffVarReal) :: EndowQFieldValueVar  !! %-change in value (level) of endowment

! Next will be a real (eg q:200) or a Coefficient (eg q:totfac)
!	  type (GPCoeffVarReal) :: EndowQFieldQuantityCoeffOrRealMPSGE  !! MPSGE quantity (initial level) of endowment

	        if(MixedTABFile) then
! Levels variable
	          call DeclareGPLevelsVar(CurrentEndowmentGP%EndowQFieldQuantityCoeff, &
						CurrentEndowmentGP%EndowQFieldQuantityVar)
		else
		  call DeclareGPCoeffVar(CurrentEndowmentGP%EndowQFieldQuantityVar)
		end if

	        if(MixedTABFile) then
! Levels variable
	          call DeclareGPLevelsVar(CurrentEndowmentGP%EndowQFieldValueCoeff, CurrentEndowmentGP%EndowQFieldValueVar)
		else
	          call DeclareGPCoeffVar(CurrentEndowmentGP%EndowQFieldValueCoeff)
		end if

!  EndowQFieldQuantityCoeffOrRealMPSGE is not set up if CurrentEndowmentGP%QFieldIsExpression is true
		if(.not.CurrentEndowmentGP%QFieldIsExpression) then
!  Nothing to declare if this is a real
	         if(CurrentEndowmentGP%EndowQFieldQuantityCoeffOrRealMPSGE%type.eq.'c') then

! Only declare it if it is different from EndowQFieldQunatityCoeff (the one updated in GEMPACK)
! If this e: line has an r: field in it, need to compare EndowQFieldQuantityCoeffOrRealMPSGE with EndowUnrationedQuantityCoeff
		  DoThis = .false.
		  if(CurrentEndowmentGP%HasRField) then
	           DoThis = .not.EqualStringsIgnoreCase(CurrentEndowmentGP%EndowQFieldQuantityCoeffOrRealMPSGE%name, &
	               CurrentEndowmentGP%EndowUnrationedQuantityCoeff%name)
!		    write(*,*)'CurrentEndowmentGP%EndowUnrationedQuantityCoeff is ', &
!			CurrentEndowmentGP%EndowUnrationedQuantityCoeff%name
		  else
	           DoThis = .not.EqualStringsIgnoreCase(CurrentEndowmentGP%EndowQFieldQuantityCoeffOrRealMPSGE%name, &
	               CurrentEndowmentGP%EndowQFieldQuantityCoeff%name)
!		    write(*,*)'CurrentEndowmentGP%EndowQFieldQuantityCoeff is ', &
!			CurrentEndowmentGP%EndowQFieldQuantityCoeff%name
		  end if

! Temporary
!		  if(DoThis) then
!		    write(*,*)'DoThis is true. CurrentEndowmentGP%EndowQFieldQuantityCoeffOrRealMPSGE is ', &
!			CurrentEndowmentGP%EndowQFieldQuantityCoeffOrRealMPSGE%name
!		  else
!		    write(*,*)'DoThis is false. CurrentEndowmentGP%EndowQFieldQuantityCoeffOrRealMPSGE is ', &
!			CurrentEndowmentGP%EndowQFieldQuantityCoeffOrRealMPSGE%name
!		  end if 


	          if(DoThis) then
	            call DeclareGPCoeffVar(CurrentEndowmentGP%EndowQFieldQuantityCoeffOrRealMPSGE)
	          end if

	         end if

!		 "End if(.not.CurrentEndowmentGP%QFieldIsExpression) then"
		else if(CurrentEndowmentGP%QFieldIsExpression) then
! Run through the expression, checking the coefficients we find. Declare the coefficients and read
!  them if not already declared.
! Now only do this when GPCoeffMPSGEPass is false. [When GPCoeffMPSGEPass is true, declare them if they
!  occur outside an expression, when they may be levels variables. By calling DeclareAllInThisGPCoeffMPSGEList
!  only when GPCoeffPass is false, only declare them as Coefficient(Parameter)s if they do not occur
!   outside an expression.]
	          if(.not.GPCoeffMPSGEPass) then
! Get the GPCoeffMPSGEs into GPCoeffMPSGEHere
	            ThisExpression = ExpressionToGPSyntax(CurrentEndowmentGP%QFieldExpressionString, GPCoeffMPSGEHere)
! Declare all things in GPCoeffMPSGEHere (which are not already declared)
		    call DeclareAllInThisGPCoeffMPSGEList(GPCoeffMPSGEHere)
	          end if ! if(.notGPCoeffMPSGEPass) then
	        end if

! EndowRFieldCoeff  !! level of r: variable
		if(CurrentEndowmentGP%HasRField) then
! [26/04/04] EndowRFieldCoeff is now declared in the $auxiliary section near start of TAB file, so omit it here
!NO	          if(MixedTABFile) then
! Levels variable
!NO	            call DeclareGPLevelsVar(CurrentEndowmentGP%EndowRFieldCoeff, CurrentEndowmentGP%EndowRFieldVar)
!NO		  else
!NO	            call DeclareGPCoeffVar(CurrentEndowmentGP%EndowRFieldCoeff)
!NO		  end if

	          if(MixedTABFile) then
! Levels variable
	            call DeclareGPLevelsVar(CurrentEndowmentGP%EndowUnRationedQuantityCoeff, &
							CurrentEndowmentGP%EndowUnRationedQuantityVar)
		  else
	            call DeclareGPCoeffVar(CurrentEndowmentGP%EndowUnRationedQuantityCoeff)
		  end if

		end if ! if(CurrentEndowmentGP%HasRField) then

! Increment NumEndowmentGPDone
	        NumEndowmentGPDone = NumEndowmentGPDone + 1

	        CurrentEndowmentGP => CurrentEndowmentGP%next
	      end do ! while

!	     End "if(fnGP%NumEFields.gt.0) then"
	    end if


!	   End "else if(fnf%label.eq.'$demand') then"
	  end if


	  if(fnf%label.eq.'$prod'.or.fnf%label.eq.'$demand') then
! Do other statements associated with this function
	    call DoRestTABOneFunctionGP(fnGP)
	  end if


	  fnGP => fnGP%next
	end do

! End the two BigCoeffPasses
      end do ! do BigCoeffPass=1,2

! Write the market clearing equations
	Messages%PreLine(1) = 'Doing the market clearing equations'
!  Re-initialize 'pre' messages past number 1
	call InitializeMessages('pre',1)
!	write(*,*) trim(Messages%PreLine(1))
	call DoMarketClearingEquations

! Process the constraints
	Messages%PreLine(1) = 'Doing the constraints'
!  Re-initialize 'pre' messages past number 1
	call InitializeMessages('pre',1)
	write(*,*) trim(Messages%PreLine(1))
	call DoConstraints

! Blank line at end of TAB file
	call WriteOneLineToTAB(' ')


! Write top of CMF file
	Messages%PreLine(1) = 'Doing the Command file'
!  Re-initialize 'pre' messages past number 1
	call InitializeMessages('pre',1)
	write(*,*) trim(Messages%PreLine(1))
	call WriteCMFFile

! Write TABLO STI file
	Messages%PreLine(1) = 'Doing the TABLO STI file'
!  Re-initialize 'pre' messages past number 1
	call InitializeMessages('pre',1)
	write(*,*) trim(Messages%PreLine(1))
	call WriteTABSTIFile

! Close and keep the output files
	close(unit=iotabgp, status='keep')
	close(unit=iocmfgp, status='keep')
	close(unit=iotabstigp, status='keep')

	if(WalrasNumeraireString.eq.' ') then
! Did not find equation to omit. Warn the user. [Also put warning in Command file.]
! Do this at the end of the run.
	  Messages%PreLine(1) = 'checking the market clearing equations'
!  Re-initialize 'pre' messages past number 1
	  call InitializeMessages('pre',1)
	  call GiveWarning('Sorry, the program did not identify an equation to omit to satisfy'// &
	    '\n  Walras law. You will need to modify the TAB file to omit one equation.'// &
	    '\n  ** You cannot carry out a simulation until you have done this. **')
	end if ! if(WalrasNumeraireString.eq.' ') then

	write(*,fmt)'Ended routine ConvertToGP'

	return
	end subroutine ConvertToGP

	subroutine DoRestTABOneFunctionGP(ThisFunctionGP)
! Input
	type (functionGP), pointer :: ThisFunctionGP
! Local
	type (function), pointer :: ThisFunctionMPSGE
	integer :: kpass, NumNetputGPDone, kcoeff, CurrentTaxNumber, NumEndowmentGPDone
	type (netputGP), pointer :: CurrentNetputGP
	type (taxGP), pointer :: CurrentTaxGP
	type (endowmentGP), pointer :: CurrentEndowmentGP
	character(len=512) OutputString, OutputStringAlls, OutputString1, OutputString2
	character(len=512) OutputStringArgs, CoeffVarName, DeclarationStart
	integer :: LenStart, LenSoFar, LenAlls, StartPass, EndPass
	logical :: RHSDone
	character(len=1024) :: IOLineConditionExpression, ProdException, ProdExceptionString, IOCondExpression
	type (GPCoeffMPSGE), pointer :: GPCoeffMPSGEHere

10005	format(a)

	ThisFunctionMPSGE => ThisFunctionGP%functionMPSGE

! When GPCoeffMPSGEPass is true, just do reads (in fact only reads of coeff in GPCoeffMPSGEList)
! When GPCoeffMPSGEPass is false, may still need to do some reads, and do all the other statements.
! [If a coeff appears only in an expression in the MGE file, need to declare it and read its values
!   when GPCoeffMPSGEPass is false.]
! Set StartPass and EndPass accordingly
	if(GPCoeffMPSGEPass) then
	  StartPass = 1
	  EndPass = 1
	else
	  StartPass = 1
	  EndPass = 4
	end if

	do kpass=StartPass, EndPass

! Do Reads when KPASS=1
! Do Formulas when KPASS=2
! Do Equations when KPASS=3
! Do Updates when KPASS=4

	  if (ThisFunctionMPSGE%firstrecord%firstfield%label.eq.'$prod') then

	    ProdException = ThisFunctionGP%functionMPSGE%firstrecord%firstfield%condtn
	    if(ProdException.ne.' ') then
! Translate the exception to GEMPACK. Complete logical expression if necessary
	      ProdExceptionString = ExpressionToGPSyntax2(ProdException, .true., 'NE 0', &
		.false., GPCoeffMPSGEHere)
!	      write(*,*)'ProdExceptionString = ', trim(ProdExceptionString)
	    end if ! if(ProdException.ne.' ') then

	    if(kpass.eq.1) then
	      call DoReadsOneProdFunction(ThisFunctionGP)
	    end if

	    CurrentNetputGP => ThisFunctionGP%FirstNetputGP
	    NumNetputGPDone = 0
	    do while(NumNetputGPDone.lt.ThisFunctionGP%NumIFields+ThisFunctionGP%NumOFields)

	      if(kpass.eq.2.or.kpass.eq.3) then
! [03/06/04] Put out comment showing start of this part of the code for this line
! [Not KPASS=4 since currently are no updates written]
	        OutputString = '! code associated with line '//&
		  trim(CurrentNetputGP%netputMPSGE%f%label)//':'//&
		  trim(CurrentNetputGP%netputMPSGE%f%data)//' !'
	        call WriteOneLineToTAB(' ')  ! Blank line first 
	        call WriteOneLineToTAB(OutputString)
	      end if ! if(kpass.eq.2.or.kpass.eq.3) then
	 
! [03/06/04] Is there a condition attached to this i: or o: line? If so convert the
!   condition to a GEMPACK expression.

	      IOLineConditionExpression = ' '
	      if(CurrentNetputGP%netputMPSGE%f%condtn.ne.' ') then
! Translate to GEMPACK, adding 'NE 0' at the end if relevant
	      	IOCondExpression = ExpressionToGPSyntax2(CurrentNetputGP%netputMPSGE%f%condtn, .true., 'NE 0', &
	        	      .false., GPCoeffMPSGEHere)
! First put any condition associated with this prod: function
	        if(ProdException.ne.' ') then
	          IOLineConditionExpression = '['//trim(ProdExceptionString)//'] AND ['//trim(IOCondExpression)//']'
		else
	          IOLineConditionExpression = trim(IOCondExpression)
	        end if ! if(ProdException.ne.' ') then
	      else if(CurrentNetputGP%netputMPSGE%f%condtn.eq.' ') then
	        if(ProdException.ne.' ') then
	          IOLineConditionExpression = trim(ProdExceptionString)
	        end if ! if(ProdException.ne.' ') then
	      end if ! if(CurrentNetputGP%netputMPSGE%f%condtn.ne.' ') then

! [All reads for this function have already been done]
	      if(kpass.eq.2) then
! In the mixedTABFile case, DoFormulasOneIOLine may write "formula & equation" statements
	        call DoFormulasOneIOLine(CurrentNetputGP, IOLineConditionExpression)
	      else if(kpass.eq.3) then
	        call DoEquationsOneIOLine(ThisFunctionGP, CurrentNetputGP, IOLineConditionExpression)
	      else if(kpass.eq.4) then
	        call DoUpdatesOneIOLine(CurrentNetputGP)
	      end if

	      if(kpass.eq.2.or.kpass.eq.3) then
! [03/06/04] Put out comment showing start of this part of the code for this line
! [Not KPASS=4 since currently are no updates written]
	        OutputString = '! End of code associated with line '//&
		  trim(CurrentNetputGP%netputMPSGE%f%label)//':'//&
		  trim(CurrentNetputGP%netputMPSGE%f%data)//' !'
	        call WriteOneLineToTAB(OutputString)
	      end if ! if(kpass.eq.2.or.kpass.eq.3) then

! Increment NumNetputGPDone
	      NumNetputGPDone = NumNetputGPDone + 1

! Go on to the next netputGP for this function
	      CurrentNetputGP => CurrentNetputGP%next

	    end do ! while

	    if(kpass.eq.2) then
! [06/04/04] Need to delay these until KPASS=3 so that values on RHS are set up
! Formulas for Total revenue and cost
!LATER	      call DoCostRevenueFormulasOneProdFunction(ThisFunctionGP)
	    else if(kpass.eq.3) then

! [03/06/04] Put out comment showing start of this part of the code for this line
	      OutputString = '! Costs and Revenue for '//&
		  trim(ThisFunctionGP%functionMPSGE%firstrecord%firstfield%label)//':'//&
		  trim(ThisFunctionGP%functionMPSGE%firstrecord%firstfield%data)//' !'
	      call WriteOneLineToTAB(' ')  ! Blank line first 
	      call WriteOneLineToTAB(OutputString)

! Formulas for Total revenue and cost
	      call DoCostRevenueFormulasOneProdFunction(ThisFunctionGP)
! Equations for total revenue and cost, and zero profit equation
	      call DoEquationsOneProdFunction(ThisFunctionGP)

! [03/06/04] Put out comment showing start of this part of the code for this line
	      OutputString = '! End of Costs and Revenue for '//&
		  trim(ThisFunctionGP%functionMPSGE%firstrecord%firstfield%label)//':'//&
		  trim(ThisFunctionGP%functionMPSGE%firstrecord%firstfield%data)//' !'
	      call WriteOneLineToTAB(OutputString)

	    end if

!	   End "if (ThisFunctionMPSGE%firstrecord%firstfield%label.eq.'$prod') then"
	  else if (ThisFunctionMPSGE%firstrecord%firstfield%label.eq.'$demand') then

	    if(ThisFunctionGP%NumEFields.gt.0) then
	      CurrentEndowmentGP => ThisFunctionGP%FirstEndowmentGP
	      NumEndowmentGPDone = 0
	      do while(NumEndowmentGPDone.lt.ThisFunctionGP%NumEFields)

	        if(kpass.eq.1) then
!  Read value in q: field
	          call DoReadsOneEndowmentLine(CurrentEndowmentGP)
		else if(kpass.eq.2) then
	          call DoFormulasOneEndowmentLine(CurrentEndowmentGP)
		else if(kpass.eq.3) then
!  Linear equation for %-change in value of q: field
	          call DoEquationsOneEndowmentLine(CurrentEndowmentGP)
	        end if

! Increment NumEndowmentGPDone
	        NumEndowmentGPDone = NumEndowmentGPDone + 1

! Go on to the next endowmentGP for this function
	        CurrentEndowmentGP => CurrentEndowmentGP%next
	      end do ! while

!	     End "if(ThisFunctionGP%NumEIFields.gt.0) then"
	    end if

	    if(kpass.eq.3) then
!		Levels equation for total income - must be done after DoEquationsOneEndowmentLine
	      call DoEquationsOneDemandFunction(ThisFunctionGP)
	    end if

!	   End "else if (ThisFunctionMPSGE%firstrecord%firstfield%label.eq.'$demand') then"
	  end if

	end do ! do kpass=StartPass, EndPass

	return
	end subroutine DoRestTABOneFunctionGP

	recursive subroutine WriteOneLineToTAB(ThisLine) 
!! Routine WriteOneLineToTAB: Write one line, breaking it up into lines of at most 80 character if necessary
! Input
	character (len=*), intent(in) :: ThisLine
! Local
	integer :: n1, OrigLength
	character (len=512) :: TempLine

10005	format(a)

	OrigLength = LEN_TRIM(ThisLine)
	if(OrigLength.le.80) then
	  write(iotabgp, 10005) trim(ThisLine)
	else
! Try to break the line at sensible places.
! First try "="
	  n1 = INDEX(ThisLine,'=')
	  if(n1.eq.0.or.n1.eq.OrigLength) then
! Next try "]," which may end condition in IF test
	    n1=INDEX(ThisLine,'],')
	  end if
	  if(n1.eq.0.or.n1.eq.OrigLength) then
! Next try "}," which may end condition in IF test
	    n1=INDEX(ThisLine,'},')
	  end if
	  if(n1.eq.0.or.n1.eq.OrigLength) then
! Next try "+"
	    n1=INDEX(ThisLine,'+')
	  end if
	  if(n1.eq.0.or.n1.eq.OrigLength) then
! Next try "-"
	    n1=INDEX(ThisLine,'-')
	  end if
	  if(n1.eq.0.or.n1.eq.OrigLength) then
! Next try "*"
	    n1=INDEX(ThisLine,'*')
	  end if
! If N1=OrigLength, have not split it
	  if(n1.gt.0.and.n1.lt.OrigLength) then
! Write as 2 lines
! First line ends at "=","+" or "-" etc.
	    write(*,*)'Split line at = etc. Writing line 1, n1=', n1
	    write(*,*)'ThisLine is:',trim(ThisLine)
	    call WriteOneLineToTAB(ThisLine(1:n1))	
	    write(*,*)'Split line at = etc. Writing line 2'
	    call WriteOneLineToTAB(ThisLine(n1+1:))
	    write(*,*)'Split line at = etc. Written line 2'
	  else
! Try to break before things like SUM
	    TempLine = ThisLine
	    call lower(TempLine)
	    n1=INDEX(TempLine,'sum')
! If N1=OrigLength, have not split it
	    if(n1.gt.1.and.n1.lt.OrigLength) then
! Write as 2 lines [Note that the first part may be all blanks]
	      TempLine = ThisLine(1:n1-1)
	      if(TempLine.ne.' ') then
	        call WriteOneLineToTAB(TempLine(1:n1-1))
	      end if
	      call WriteOneLineToTAB(ThisLine(n1:))
	    else
	      call InternalErrorStop( &
	        'WriteOneLineToTAB: Line is too long. Length is:'//PosintToString(OrigLength) // &
		  '\n Line is:'// &
	            '\n'//trim(ThisLine) )
	    end if
	  end if
	end if ! if(OrigLength.le.80) then..else..

	return
	end subroutine WriteOneLineToTAB 

	subroutine DoUpdatesOneIOLine(CurrentNetputGP)
! Input
	type (netputGP), pointer :: CurrentNetputGP
! Local
	integer :: kcoeff, CurrentTaxNumber
	type (taxGP), pointer :: CurrentTaxGP
	character(len=512) OutputString, OutputStringAlls, OutputString1, OutputString2
	character(len=512) OutputStringArgs, CoeffVarName, DeclarationStart
	integer :: LenStart, LenSoFar, LenAlls
	logical :: RHSDone

10005	format(a)

! Taxes
	if(CurrentNetputGP%NumTaxTypes.gt.0) then

! Run through the taxes
		CurrentTaxGP => CurrentNetputGP%FirstTaxGP
		CurrentTaxNumber = 0
		do while(CurrentTaxNumber.lt.CurrentNetputGP%NumTaxTypes)

! Update TaxRateCoeff  !! rate of tax (number like 0.13)
! Update TaxRevenueCoeff  !! tax revenue

! in MixedTABFile case, never need to write these updates
		  if(LinearTABFile) then
  
		    do kcoeff=1,2
! Do TaxRateCoeff when KCOEFF=1
! Do TaxRevenueCoeff when KCOEFF=2

		      DeclarationStart = 'Update (Change)'
		      LenStart = LEN_TRIM(DeclarationStart)

		      OutputString=trim(DeclarationStart)//' '
		      LenSoFar = LenStart+1

		      call ArgToAllsGP(CurrentTaxGP%TaxRateCoeff%arg, OutputStringAlls)
		      OutputStringAlls = trim(OutputStringAlls)
		      LenAlls = LEN_TRIM(OutputStringAlls)
		      if(OutputStringAlls.ne.'') then
! Output Start now if ncessary
	  	        if(LenStart.gt.25) then
			  call WriteOneLineToTAB(OutputString)
	    		  OutputString = ' '
	  	        end if
	  	        OutputString = trim(OutputString)//' '//OutputStringAlls
		      end if
		      LenSoFar = LEN_TRIM(OutputString)

! Output a line now if ncessary
		      if(LenSoFar.gt.40) then
			call WriteOneLineToTAB(OutputString)
	  	        OutputString = ' '
		      end if

! The LHS name
		      if(kcoeff.eq.1) then
		        CoeffVarName = CurrentTaxGP%TaxRateCoeff%name
		      else if(kcoeff.eq.2) then
		        CoeffVarName = CurrentTaxGP%TaxRevenueCoeff%name
		      end if
		      OutputString = trim(OutputString)//' '//trim(CoeffVarName)
! The arguments
		      OutputStringArgs = ''
!
		      if(OutputStringAlls.ne.'') then

		        call ArgToGP(CurrentTaxGP%TaxRateCoeff%arg, OutputStringArgs)
! Add opening ( and closing )
		        OutputStringArgs = '('//trim(OutputStringArgs)//')'
! Add to OutputString
		        OutputString = trim(OutputString)//OutputStringArgs
		      end if
! '='
		      OutputString = trim(OutputString)//' = '

! Output a line now if ncessary
		      if(LenSoFar.gt.40) then
			call WriteOneLineToTAB(OutputString)
	  	        OutputString = ' '
		      end if

! RHS name
		      if(kcoeff.eq.1) then
		        CoeffVarName = CurrentTaxGP%TaxRateChangeVar%name
		      else if(kcoeff.eq.2) then
		        CoeffVarName = CurrentTaxGP%TaxRevenueChangeVar%name
		      end if
		      OutputString = trim(OutputString)//' '//trim(CoeffVarName)

! RHS arguments (same as on LHS in this case) and ";"
		      OutputString = trim(OutputString)//trim(OutputStringArgs)//' ;'		

! Complete the statement
		      call WriteOneLineToTAB(OutputString)

		    end do ! kcoeff=1,2

!		   End "if(LinearTABFile) then"
		  end if

		  CurrentTaxNumber = CurrentTaxNumber + 1
		  CurrentTaxGP => CurrentTaxGP%next
		end do ! while

!	       End "if(CurrentNetputGP%NumTaxTypes.gt.0) then"
	end if

! Update IOQFieldValueCoeff
		
! This Update is not needed in MixedTABFile case if are any taxes on this line
! [06/04/04] Nor is it ever needed in MixedTABFile case
!WAS	if(LinearTABFile .or. CurrentNetputGP%NumTaxTypes.eq.0) then
	if(LinearTABFile) then
 
		DeclarationStart = 'Update'
		LenStart = LEN_TRIM(DeclarationStart)

		OutputString=trim(DeclarationStart)//' '
		LenSoFar = LenStart+1

		call ArgToAllsGP(CurrentNetputGP%IOQFieldValueCoeff%arg, OutputStringAlls)
		OutputStringAlls = trim(OutputStringAlls)
		LenAlls = LEN_TRIM(OutputStringAlls)
		if(OutputStringAlls.ne.'') then
! Output Start now if ncessary
	  	        if(LenStart.gt.25) then
			  call WriteOneLineToTAB(OutputString)
	    		  OutputString = ' '
	  	        end if
	  	        OutputString = trim(OutputString)//' '//OutputStringAlls
		end if
		LenSoFar = LEN_TRIM(OutputString)

! Output a line now if ncessary
		if(LenSoFar.gt.40) then
			call WriteOneLineToTAB(OutputString)
	  	        OutputString = ' '
		end if

! The LHS name
		CoeffVarName = CurrentNetputGP%IOQFieldValueCoeff%name
		OutputString = trim(OutputString)//' '//trim(CoeffVarName)
! The arguments
		OutputStringArgs = ''
!
		if(OutputStringAlls.ne.'') then

		  call ArgToGP(CurrentNetputGP%IOQFieldValueCoeff%arg, OutputStringArgs)
! Add opening ( and closing )
		  OutputStringArgs = '('//trim(OutputStringArgs)//')'
! Add to OutputString
		  OutputString = trim(OutputString)//OutputStringArgs
		end if
! '='
		OutputString = trim(OutputString)//' = '

! Output a line now if ncessary
		if(LenSoFar.gt.40) then
			call WriteOneLineToTAB(OutputString)
	  	        OutputString = ' '
		end if

! RHS
		RHSDone = .false.
		if(CurrentNetputGP%NumTaxTypes.ge.1) then
		  if(CurrentNetputGP%netputMPSGE%f%label.eq.'o') then
! Use IOQFieldValueVar to do the update
		    CoeffVarName = CurrentNetputGP%IOQFieldValueVar%name
		    OutputString = trim(OutputString)//' '//trim(CoeffVarName)
! RHS arguments (same as on LHS in this case) and ";"
		    OutputString = trim(OutputString)//trim(OutputStringArgs)//' ;'		
! Complete the statement
		    call WriteOneLineToTAB(OutputString)
		    RHSDone = .true .
		  end if
		end if

		if(.not.RHSDone) then

! Use product update, price variable is IOPriceVar and quantity variable is IOQFieldQuantityVar 
		  call CoeffVarRealToGP(CurrentNetputGP%IOPriceVar, OutputString1) 
		  call CoeffVarRealToGP(CurrentNetputGP%IOQFieldQuantityVar, OutputString2)
		  OutputString = trim(OutputString)//' '//trim(OutputString1)// &
				' * '//trim(OutputString2)//' ;' 
! Complete the statement
		  call WriteOneLineToTAB(OutputString)
		  RHSDone = .true .

!		 End "if(.not.RHSDone) then"
		end if

	end if ! if(LinearTABFile) then

	end subroutine DoUpdatesOneIOLine

	subroutine DoOneReadIfNotAlreadyDone(CoeffNameToRead)
! input
	character (len=*), intent(in) :: CoeffNameToRead
! Local
	character(len=512) OutputString
	character (len=llhd) HeadString
	logical :: found
	logical ThisIsInGPCoeffMPSGEList, DoThisNow, ThisHasBeenDeclared
	type(GPCoeffMPSGE), pointer :: GPCoeffMPSGEFound

! Has this already been read?
	call IsNameInGPReadList(CoeffNameToRead, Found)



	if(.not.Found) then

! When GPCoeffMPSGEPass is true, only read coefficients in GPCoeffMPSGEList which 
!  have been declared already. [Coefficients occurring only in expressions in the MGE file
!   will be in GPCoeffMPSGEList but will not be declared when GPCoeffMPSGEPass is true since they are 
!   only declared via call to routine DeclareAllInThisGPCoeffMPSGEList, and this is only called
!   when GPCoeffMPSGEPass is false - see routine ConvertToGP.] 
! When GPCoeffMPSGEPass is false, always set DoThisNow true - then read this if it has not
!   already been read.
! Check this. Return if don't need to do this on this pass.
	  call IsInGPCoeffMPSGEList(CoeffNameToRead, ThisIsInGPCoeffMPSGEList, GPCoeffMPSGEFound)
	  if(GPCoeffMPSGEPass) then
	    ThisHasBeenDeclared = HasBeenDeclaredGP('cs', CoeffNameToRead)
	    DoThisNow = ThisIsInGPCoeffMPSGEList .and. ThisHasBeenDeclared 
	  else
	    DoThisNow = .true.
	  end if
	  if(.not.DoThisNow) Return		

	  if(NumGPReads.eq.0) then
! Declare File Input
	      call WriteOneLineToTAB(' ')
	      call WriteOneLineToTAB('File Input # contains data and set elements # ;')
	      call WriteOneLineToTAB(' ')
	  end if
! Find header to read this from
	  call GetReadHeader(CoeffNameToRead, HeadString)
! Temporary
!	  write(*,*)'DoOneReadIfNotAlreadyDone. Read of ', trim(CoeffNameToRead),' from header ', trim(HeadString)
 
	  OutputString = 'Read '//trim(CoeffNameToRead)// &
		  ' from File Input Header "'//HeadString//'" ;'
	  call WriteOneLineToTAB(OutputString)
! Add this read to GPReadList
	  call AddToGPReadList(CoeffNameToRead)
	  NumGPReads = NumGPReads + 1
	end if ! if(.not.Found) then

	return
	end subroutine DoOneReadIfNotAlreadyDone

	subroutine DoReadsOneProdFunction(ThisFunctionGP)
! Input
	type (functionGP), pointer :: ThisFunctionGP
! Local
	integer :: NumNetputGPDone
	type (netputGP), pointer :: CurrentNetputGP
	character(len=512) OutputString, ElastName
	character (len=4) HeadString
	logical :: found, DoThis
	type (GPCoeffVarReal) :: ThisElast
	integer :: kpass

10005	format(a)
 
	CurrentNetputGP => ThisFunctionGP%FirstNetputGP
	NumNetputGPDone = 0
	do while(NumNetputGPDone.lt.ThisFunctionGP%NumIFields+ThisFunctionGP%NumOFields)

	  call DoReadsOneIOLine(CurrentNetputGP)

! Increment NumNetputGPDone
	  NumNetputGPDone = NumNetputGPDone + 1

! Go on to the next netput for this function
	  CurrentNetputGP => CurrentNetputGP%next

	end do ! while

! Read the elasticities if they are not reals
	do kpass=1,2

! SElast when KPASS=1
! TElast when KPASS=2
	  if(kpass.eq.1) then
	    DoThis = ThisFunctionGP%SElastPresent
	  else if(kpass.eq.2) then
	    DoThis = ThisFunctionGP%TElastPresent
	  end if
	  if(DoThis) then
	    if(kpass.eq.1) then
	      ThisElast = ThisFunctionGP%SElasticity
	    else if(kpass.eq.2) then
	      ThisElast = ThisFunctionGP%TElasticity
	    end if
! Nothing to read if this is a real
	    if(ThisElast%type.eq.'c') then
	      call DoOneReadIfNotAlreadyDone(ThisElast%name)
	    end if	   
	  end if
	end do ! kpass

	return
	end subroutine DoReadsOneProdFunction

	subroutine DoReadsOneIOLine(CurrentNetputGP)
! Input
	type (netputGP), pointer :: CurrentNetputGP
! Local
	integer :: CurrentTaxNumber
	type (taxGP), pointer :: CurrentTaxGP
	character (len=1024) :: ThisExpression
	type (GPCoeffMPSGE), pointer :: GPCoeffMPSGEHere

10005	format(a)

! Taxes
	if(CurrentNetputGP%NumTaxTypes.gt.0) then

! Run through the taxes
	  CurrentTaxGP => CurrentNetputGP%FirstTaxGP
	  CurrentTaxNumber = 0
	  do while(CurrentTaxNumber.lt.CurrentNetputGP%NumTaxTypes)

!----------------------------------------------------------------
! [26/04/04] p: field if present
	    if(associated(CurrentNetputGP%netputMPSGE%pref)) then
	      ThisExpression = ExpressionToGPSyntax(CurrentNetputGP%PFieldExpressionString, GPCoeffMPSGEHere)
! Read all things in GPCoeffMPSGEHere (which are not already read)
	      call DoReadsAllInGPCoeffMPSGEList(GPCoeffMPSGEHere)
	    end if ! if(associated(CurrentNetputGP%netputMPSGE%pref)) then
!----------------------------------------------------------------

	    if(.not.CurrentTaxGP%HasNField) then
	      if(.not.CurrentTaxGP%TFieldIsExpression) then
! Read TaxRateCoeffOrRealMPSGE if it is not a real number
	        if(CurrentTaxGP%TaxRateCoeffOrRealMPSGE%type.eq.'c') then
	          call DoOneReadIfNotAlreadyDone(CurrentTaxGP%TaxRateCoeffOrRealMPSGE%name)
	        end if
	      else if(CurrentTaxGP%TFieldIsExpression) then
! [26/04/04] Get the GPCoeffMPSGEs into GPCoeffMPSGEHere
	        ThisExpression = ExpressionToGPSyntax(CurrentTaxGP%TFieldExpressionString, GPCoeffMPSGEHere)
! Read all things in GPCoeffMPSGEHere (which are not already read)
	        call DoReadsAllInGPCoeffMPSGEList(GPCoeffMPSGEHere)
	      end if ! else if(CurrentTaxGP%TFieldIsExpression) then
	    else ! if(CurrentTaxGP%HasNField) then
! Read NFieldCoeff
	      call DoOneReadIfNotAlreadyDone(CurrentTaxGP%NFieldCoeff%name)
! Read things in m: field
	      if(.not.CurrentTaxGP%MFieldIsExpression) then
! Read TaxRateCoeffOrRealMPSGE if it is not a real number
	        if(CurrentTaxGP%MFieldCoeffOrRealMPSGE%type.eq.'c') then
	          call DoOneReadIfNotAlreadyDone(CurrentTaxGP%MFieldCoeffOrRealMPSGE%name)
	        end if
	      else if(CurrentTaxGP%MFieldIsExpression) then
! [26/04/04] Get the GPCoeffMPSGEs into GPCoeffMPSGEHere
	        ThisExpression = ExpressionToGPSyntax(CurrentTaxGP%MFieldExpressionString, GPCoeffMPSGEHere)
! Read all things in GPCoeffMPSGEHere (which are not already read)
	        call DoReadsAllInGPCoeffMPSGEList(GPCoeffMPSGEHere)
	      end if ! else if(CurrentTaxGP%MFieldIsExpression) then
	    end if ! if(.not.CurrentTaxGP%HasNField) then..else..

	    CurrentTaxNumber = CurrentTaxNumber + 1
	    CurrentTaxGP => CurrentTaxGP%next

	  end do ! while

!	       End "if(CurrentNetputGP%NumTaxTypes.gt.0) then"
	end if

! Read IOQFieldQuantityCoeffOrRealMPSGE if it is not a real number and if it is set up
	if(.not.CurrentNetputGP%QFieldIsExpression) then
	  if(CurrentNetputGP%IOQFieldQuantityCoeffOrRealMPSGE%type.eq.'c') then
	    call DoOneReadIfNotAlreadyDone(CurrentNetputGP%IOQFieldQuantityCoeffOrRealMPSGE%name)
	  end if
	else if(CurrentNetputGP%QFieldIsExpression) then
! Get the GPCoeffMPSGEs into GPCoeffMPSGEHere
	  ThisExpression = ExpressionToGPSyntax(CurrentNetputGP%QFieldExpressionString, GPCoeffMPSGEHere)
! Read all things in GPCoeffMPSGEHere (which are not already read)
	  call DoReadsAllInGPCoeffMPSGEList(GPCoeffMPSGEHere)
	end if
		
	return
	end subroutine DoReadsOneIOLine

	subroutine DoReadsOneEndowmentLine(CurrentEndowmentGP)
! Input
	type (endowmentGP), pointer :: CurrentEndowmentGP
! Local
	character (len=1024) :: ThisExpression
	type (GPCoeffMPSGE), pointer :: GPCoeffMPSGEHere

10005	format(a)

! Read EndowQFieldQuantityCoeffOrRealMPSGE if it is not a real number and it is set up
	if(.not.CurrentEndowmentGP%QFieldIsExpression) then
	  if(CurrentEndowmentGP%EndowQFieldQuantityCoeffOrRealMPSGE%type.eq.'c') then
	    call DoOneReadIfNotAlreadyDone(CurrentEndowmentGP%EndowQFieldQuantityCoeffOrRealMPSGE%name)
	  end if
	else if(CurrentEndowmentGP%QFieldIsExpression) then
! Get the GPCoeffMPSGEs into GPCoeffMPSGEHere
	  ThisExpression = ExpressionToGPSyntax(CurrentEndowmentGP%QFieldExpressionString, GPCoeffMPSGEHere)
! Read all things in GPCoeffMPSGEHere (which are not already read)
	  call DoReadsAllInGPCoeffMPSGEList(GPCoeffMPSGEHere)
	end if

! Read EndowRFieldCoeff if HasRField is true
	if(CurrentEndowmentGP%HasRField) then
	  call DoOneReadIfNotAlreadyDone(CurrentEndowmentGP%EndowRFieldCoeff%name)
	end if
		
	return
	end subroutine DoReadsOneEndowmentLine

	subroutine DoFormulasOneEndowmentLine(ThisEndowmentGP)
! Input
	type(endowmentGP), pointer :: ThisEndowmentGP
! Local
	logical :: DoThis
	type (GPCoeffVarReal) :: LHSCoeff  
	character(len=512) OutputString, TempString, TempString2, GEMPACKStyleExpression
	type(GPCoeffMPSGE), pointer :: GPCoeffMPSGEHere	

! Formula(Initial) for EndowQFieldQuantityCoeff or EndowUnrationedQuantityCoeff if q: field is an
!  expression or a number

!WAS	DoThis = .false.
!WAS	if(ThisEndowmentGP%QFieldIsExpression) then
!WAS	  DoThis = .true.
!WAS	else
!WAS	  DoThis = .not.(ThisEndowmentGP%EndowQFieldQuantityCoeffOrRealMPSGE%type.eq.'c')
!WAS	end if

! [15/04/04] QFieldNeedGEMPACKCoeff is now the neater way to tell if need Formula(Initial).
	DoThis = ThisEndowmentGP%QFieldNeedGEMPACKCoeff 

	if(DoThis) then

!	  type (GPCoeffVarReal) :: EndowQFieldQuantityCoeff  !! quantity (level) of each endowment q: field  
!	  type (GPCoeffVarReal) :: EndowUnrationedQuantityCoeff  !! unrationed quantity of endowment (level)

! LHS coefficient is EndowQFieldQuantityCoeff if no r: field, otherwise is EndowUnrationedQuantityCoeff
	  if(ThisEndowmentGP%HasRField) then
	    LHSCoeff = ThisEndowmentGP%EndowUnrationedQuantityCoeff
	  else
	    LHSCoeff = ThisEndowmentGP%EndowQFieldQuantityCoeff
	  end if

! Formula keyword and quantifiers
	  call ArgToAllsGP(LHSCoeff%arg, TempString)
	  OutputString = 'Formula (Initial) '//trim(TempString)
	  call WriteOneLineToTAB(OutputString)
	
! The LHS and =
	  call CoeffVarRealToGP(LHSCoeff, TempString)
	  OutputString = trim(TempString)//' = '
	  call WriteOneLineToTAB(OutputString)

! RHS and ";"
! RHS is QFieldExpressionString when QFieldIsExpression is true
	  if(ThisEndowmentGP%QFieldIsExpression) then
! Convert this from GAMS-style syntax to GEMPACK-style syntax
	    GEMPACKStyleExpression = ExpressionToGPSyntax(ThisEndowmentGP%QFieldExpressionString, GPCoeffMPSGEHere)
	    OutputString = trim(GEMPACKStyleExpression)//' ;'
	  else
! The RHS: IOQFieldQuantityCoeffOrRealMPSGE
	    call CoeffVarRealToGP(ThisEndowmentGP%EndowQFieldQuantityCoeffOrRealMPSGE, TempString)
	    OutputString = trim(TempString)//' ;'
	  end if
! Write this out
	  call WriteOneLineToTAB('  '//OutputString)

	end if ! if(DoThis) then

	return
	end subroutine DoFormulasOneEndowmentLine

	subroutine DoFormulasOneIOLine(CurrentNetputGP, IOLineConditionExpression)
! In the mixedTABFile case, DoFormulasOneIOLine may write "formula & equation" statements
! Input
	type (netputGP), pointer :: CurrentNetputGP
	character(len=*), intent(in) :: IOLineConditionExpression
! Local
	integer :: kcoeff, CurrentTaxNumber
	type (taxGP), pointer :: CurrentTaxGP
	character(len=512) OutputString, TempString, TempString2, GEMPACKStyleExpression
	character (len=4) HeadString
	logical :: found, IsOutputLine, DoThis
	character :: PlusMinusChar  ! either '+' or '-', depending on IsOutputLine
	character (len=80) :: StatementStart
	type(GPCoeffMPSGE), pointer :: GPCoeffMPSGEHere
! [04/05/04] Now SpecialZeroQFieldValueTreatment to set %-change in value of
!   QField to zero when corresponding coefficient IOQFieldValeCoeff is zero. 
	logical, parameter :: SpecialZeroQFieldValueTreatment=.true.	

10005	format(a)

!WAS Need Formula (Initial) for value of q: field if either QFieldIsExpression, or if
!WAS   IOQFieldQuantityCoeffOrRealMPSGE is different from IOQFieldQuantityCoeff).
!WAS	DoThis = CurrentNetputGP%QFieldIsExpression .or. &
!WAS	    .not.EqualStringsIgnoreCase(CurrentNetputGP%IOQFieldQuantityCoeff%name, &
!WAS			 CurrentNetputGP%IOQFieldQuantityCoeffOrRealMPSGE%name)

! [15/04/04] QFieldNeedGEMPACKCoeff is now the neater way to tell if need Formula(Initial).
	DoThis = CurrentNetputGP%QFieldNeedGEMPACKCoeff 

	if(DoThis) then

! Formula(Initial) for IOQFieldQuantityCoeff - equal to IOQFieldQuantityCoeffMPSGE (if they are not the same) 
!	  type (GPCoeffVarReal) :: IOQFieldQuantityCoeff  !! quantity (level) of input or output
! Next will be a real (eg q:200) or a Coefficient (eg q:totfac)
!	  type (GPCoeffVarReal) :: IOQFieldQuantityCoeffOrRealMPSGE  !! MPSGE quantity (initial level) of input or output

! Formula keyword and quantifiers
	  call ArgToAllsGP(CurrentNetputGP%IOQFieldQuantityCoeff%arg, TempString)
	  OutputString = 'Formula (Initial) '//trim(TempString)
	  call WriteOneLineToTAB(OutputString)
! The LHS: IOQFieldQuantityCoeff
	  call CoeffVarRealToGP(CurrentNetputGP%IOQFieldQuantityCoeff, TempString)
	  OutputString = trim(TempString)//' = '

! Write LHS out
	  call WriteOneLineToTAB('  '//OutputString)
	  OutputString = ''

! [03/06/04] If is condition, put this into an "IF" test around RHS
	  if(IOLineConditionExpression.ne.' ') then
	    OutputString = 'IF{ '//trim(IOLineConditionExpression)//', '
	  end if ! if(IOLineConditionExpression.ne.' ') then

! RHS is QFieldExpressionString when QFieldIsExpression is true
	  if(CurrentNetputGP%QFieldIsExpression) then
! Convert this from GAMS-style syntax to GEMPACK-style syntax
	    GEMPACKStyleExpression = ExpressionToGPSyntax(CurrentNetputGP%QFieldExpressionString, GPCoeffMPSGEHere)
	    OutputString = trim(OutputString)//' '//trim(GEMPACKStyleExpression)
	  else
! The RHS: IOQFieldQuantityCoeffOrRealMPSGE
	    call CoeffVarRealToGP(CurrentNetputGP%IOQFieldQuantityCoeffOrRealMPSGE, TempString)
	    OutputString = trim(OutputString)//' '//trim(TempString)
	  end if

! [03/06/04] If is condition, put closing "}" to end "IF" test around RHS, then ";"
	  if(IOLineConditionExpression.ne.' ') then
	    OutputString = trim(OutputString)//'} ;'
	  else
! Closing ";"
	    OutputString = trim(OutputString)//' ;'
	  end if

! Write this out
	  call WriteOneLineToTAB('  '//OutputString)

	end if ! if(DoThis) then

! [04/05/04] Separate formula(initial) and linear eq when SpecialZeroQFieldValueTreatment=.true.
! Formula & Equation saying that IOQFieldValueCoeff = IOPriceCoeff * IOQFieldQuantityCoeff
! or just Formula(Initial) if SpecialZeroQFieldValueTreatment is true
	if(SpecialZeroQFieldValueTreatment) then
	  StatementStart = 'Formula (Initial)'
	  OutputString = trim(StatementStart)
	else
	  StatementStart = 'Formula & Equation'
	  OutputString = trim(StatementStart)//' E_'//CurrentNetputGP%IOQFieldValueVar%name
	end if ! if(SpecialZeroQFieldValueTreatment) then..else

! Write this out
	call WriteOneLineToTAB(OutputString)
! Mark this variable as endogenous
	call MarkAsEndogenous(CurrentNetputGP%IOQFieldValueVar)
! Quantifiers and LHS and '='
	call ArgToAllsGP(CurrentNetputGP%IOQFieldValueCoeff%arg, TempString)
	call CoeffVarRealToGP(CurrentNetputGP%IOQFieldValueCoeff, TempString2)
	OutputString = trim(TempString)//' '//trim(TempString2)//' ='
! Write this out
	call WriteOneLineToTAB('  '//OutputString)

! [03/06/04] If is condition, put this into an "IF" test around RHS
	if(IOLineConditionExpression.ne.' ') then
	    OutputString = 'IF{ '//trim(IOLineConditionExpression)//', '
	else
	    OutputString = ''
	end if ! if(IOLineConditionExpression.ne.' ') then

! RHS
	call CoeffVarRealToGP(CurrentNetputGP%IOPriceCoeff, TempString)
	call CoeffVarRealToGP(CurrentNetputGP%IOQFieldQuantityCoeff, TempString2)
	OutputString = trim(OutputString)//' '//trim(TempString)//' * '//trim(TempString2)

! [03/06/04] If is condition, put closing "}" to end "IF" test around RHS, then ";"
	if(IOLineConditionExpression.ne.' ') then
	    OutputString = trim(OutputString)//'} ;'
	else
! Closing ";"
	    OutputString = trim(OutputString)//' ;'
	end if

! Write RHS out
	call WriteOneLineToTAB('    '//OutputString)

	if(SpecialZeroQFieldValueTreatment) then
! Separate linear equation - which is necessary if coefficient IOQFieldValeCoeff is zero.
 
	  StatementStart = 'Equation (Linear)'
	  OutputString = trim(StatementStart)//' E_'//CurrentNetputGP%IOQFieldValueVar%name
! Write this out
	  call WriteOneLineToTAB(OutputString)
! Mark this variable as endogenous - done above
! ABOVE	  call MarkAsEndogenous(CurrentNetputGP%IOQFieldValueVar)
! Quantifiers and LHS and '='
	  call ArgToAllsGP(CurrentNetputGP%IOQFieldValueVar%arg, TempString)
	  call CoeffVarRealToGP(CurrentNetputGP%IOQFieldValueVar, TempString2)
	  OutputString = trim(TempString)//' '//trim(TempString2)//' ='
! Write this out
	  call WriteOneLineToTAB('  '//OutputString)

! [03/06/04] If is condition, put this into an "IF" test around RHS
	  if(IOLineConditionExpression.ne.' ') then
	    OutputString = 'IF{ '//trim(IOLineConditionExpression)//', '
	  else
	    OutputString = ''
	  end if ! if(IOLineConditionExpression.ne.' ') then

! RHS
	  call CoeffVarRealToGP(CurrentNetputGP%IOPriceVar, TempString)
	  call CoeffVarRealToGP(CurrentNetputGP%IOQFieldQuantityVar, TempString2)
	  OutputString = trim(OutputString)//' '//trim(TempString)//' + '//trim(TempString2)

! [03/06/04] If is condition, put closing "}" to end "IF" test around RHS, then ";"
	  if(IOLineConditionExpression.ne.' ') then
	    OutputString = trim(OutputString)//'} ;'
	  else
! Closing ";"
	    OutputString = trim(OutputString)//' ;'
	  end if

! Write this out
	  call WriteOneLineToTAB('    '//OutputString)
	end if ! if(SpecialZeroQFieldValueTreatment) then

! IsOutputLine and PlusMinusChar
	IsOutputLine = CurrentNetputGP%netputMPSGE%f%label.eq.'o'
	if(IsOutputLine) then
	  PlusMinusChar = '-'
	else
	  PlusMinusChar = '+'
	end if

! Taxes
	if(CurrentNetputGP%NumTaxTypes.gt.0) then

! [26/04/04] p: field (only if are some taxes)
! Formula(Initial) setting PFieldCoeff equal to whatever is in p: field
! LHS is PFieldCoeff
! Formula keyword and quantifiers
	  call ArgToAllsGP(CurrentNetputGP%PFieldCoeff%arg, TempString)
	  call CoeffVarRealToGP(CurrentNetputGP%PFieldCoeff, TempString2)
	  OutputString = 'Formula(Initial) '//trim(TempString)//' '// &
	    trim(TempString2)//' ='
! Write this out
	  call WriteOneLineToTAB(OutputString)
	  if(associated(CurrentNetputGP%netputMPSGE%pref)) then
	      GEMPACKStyleExpression = ExpressionToGPSyntax(CurrentNetputGP%PFieldExpressionString, GPCoeffMPSGEHere)
	      OutputString = trim(GEMPACKStyleExpression)//' ;'
	  else
! RHS is 1
	    OutputString = '1.0 ;'
	  end if ! if(associated(CurrentNetputGP%netputMPSGE%pref)) then..else..
! Write RHS out
	  call WriteOneLineToTAB('  '//OutputString)

! Run through the taxes
	  CurrentTaxGP => CurrentNetputGP%FirstTaxGP
	  CurrentTaxNumber = 0
	  do while(CurrentTaxNumber.lt.CurrentNetputGP%NumTaxTypes)

! Do formulas associated with this tax type
!	  type (GPCoeffVarReal) :: TaxPowerCoeff  !! power of tax
!	  type (GPCoeffVarReal) :: TaxRateCoeff  !! rate of tax (number like 0.13)
!	  type (GPCoeffVarReal) :: TaxRevenueCoeff  !! tax revenue

! quantifiers
	    call ArgToAllsGP(CurrentTaxGP%TaxRateCoeff%arg, TempString)
! Formula(Initial) for TaxRateCoeff
	    OutputString = 'Formula (Initial) '//trim(TempString)
	    
! Formula keyword and quantifiers
	    call WriteOneLineToTAB(OutputString)
! The LHS
	    if(.not.CurrentTaxGP%HasNField) then
! TaxRateCoeff
	      call CoeffVarRealToGP(CurrentTaxGP%TaxRateCoeff, TempString)
	    else ! if(CurrentTaxGP%HasNField) then
! MFieldCoeff
	      call CoeffVarRealToGP(CurrentTaxGP%MFieldCoeff, TempString)
	    end if
	    OutputString = trim(TempString)//' = '

! Write LHS out
	    call WriteOneLineToTAB('  '//OutputString)
	    OutputString = ''

! [03/06/04] If is condition, put this into an "IF" test around RHS
	    if(IOLineConditionExpression.ne.' ') then
	      OutputString = 'IF{ '//trim(IOLineConditionExpression)//', '
	    else
	      OutputString = ''
	    end if ! if(IOLineConditionExpression.ne.' ') then

	    if(.not.CurrentTaxGP%HasNField) then
! The RHS which is TaxRateCoeffOrRealMPSGE or is TFieldExpressionString
	      if(.not.CurrentTaxGP%TFieldIsExpression) then 
	        call CoeffVarRealToGP(CurrentTaxGP%TaxRateCoeffOrRealMPSGE, TempString)
	        OutputString = trim(OutputString)//' '//trim(TempString)
	      else ! if(CurrentTaxGP%TFieldIsExpression) then 
! Convert this from GAMS-style syntax to GEMPACK-style syntax
	        GEMPACKStyleExpression = ExpressionToGPSyntax(CurrentTaxGP%TFieldExpressionString, GPCoeffMPSGEHere)
	        OutputString = trim(OutputString)//' '//trim(GEMPACKStyleExpression)
	      end if ! else if(CurrentTaxGP%TFieldIsExpression) then
	    else  ! if(CurrentTaxGP%HasNField) then
! The RHS which is either MFieldCoeffOrRealMPSGE or MFieldExpressionString
	      if(.not.CurrentTaxGP%MFieldIsExpression) then 
	        call CoeffVarRealToGP(CurrentTaxGP%MFieldCoeffOrRealMPSGE, TempString)
	        OutputString = trim(OutputString)//' '//trim(TempString)
	      else ! if(CurrentTaxGP%MFieldIsExpression) then 
! Convert this from GAMS-style syntax to GEMPACK-style syntax
	        GEMPACKStyleExpression = ExpressionToGPSyntax(CurrentTaxGP%MFieldExpressionString, GPCoeffMPSGEHere)
	        OutputString = trim(OutputString)//' '//trim(GEMPACKStyleExpression)
	      end if ! else if(CurrentTaxGP%MFieldIsExpression) then
	    end if

! [03/06/04] If is condition, put closing "}" to end "IF" test around RHS, then ";"
	    if(IOLineConditionExpression.ne.' ') then
	      OutputString = trim(OutputString)//'} ;'
	    else
! Closing ";"
	      OutputString = trim(OutputString)//' ;'
	    end if

	    call WriteOneLineToTAB('  '//OutputString)

	    if(CurrentTaxGP%HasNField) then
! Formula & Equation for TaxRateCoeff - linking it to MFieldCoeff*MFieldCoeff.
!  Equation since NFieldCoeff is in it and need to adjust rate as this changes endlgenously.
	      OutputString = 'Formula & Equation '//'E_'//trim(CurrentTaxGP%TaxRateChangeVar%name)
	      call WriteOneLineToTAB(OutputString)
! quantifiers and LHS
	      call ArgToAllsGP(CurrentTaxGP%TaxRateCoeff%arg, TempString)
! The LHS
	      call CoeffVarRealToGP(CurrentTaxGP%TaxRateCoeff, TempString2)
	      OutputString = trim(TempString)//'  '//trim(TempString2)//' ='
	      call WriteOneLineToTAB('  '//OutputString)

! [03/06/04] If is condition, put this into an "IF" test around RHS
	      if(IOLineConditionExpression.ne.' ') then
	        OutputString = 'IF{ '//trim(IOLineConditionExpression)//', '
	      else
	        OutputString = ''
	      end if ! if(IOLineConditionExpression.ne.' ') then

! The RHS which is NFieldCoeff times MFieldCoeff
	      call CoeffVarRealToGP(CurrentTaxGP%NFieldCoeff, TempString2)
	      call CoeffVarRealToGP(CurrentTaxGP%MFieldCoeff, TempString)
	      OutputString = trim(TempString2)//' * '//trim(TempString)
! [03/06/04] If is condition, put closing "}" to end "IF" test around RHS, then ";"
	      if(IOLineConditionExpression.ne.' ') then
	        OutputString = trim(OutputString)//'} ;'
	      else
! Closing ";"
	        OutputString = trim(OutputString)//' ;'
	      end if

! Write RHS
	      call WriteOneLineToTAB('    '//OutputString)

! Mark TaxPowerVar as endogenous. [The LHS of this equation is TaxRateCoeff, whose
!   linear variable is TaxRateVar. But TaxRateVar is marked as endogenous when do
!   equation connecting TaxRateCoeff and TaxPowerCoeff. So here mark the power as endogenous.]
	      call MarkAsEndogenous(CurrentTaxGP%TaxPowerVar)

	    end if ! if(CurrentTaxGP%HasNField) then


! Formula or "Formula & Equation" for TaxPowerCoeff
! Formula keyword and quantifiers
	    call ArgToAllsGP(CurrentTaxGP%TaxPowerCoeff%arg, TempString)
! Set up StatementStart
	    if(MixedTABFile) then
! Add the equation name here
	      StatementStart = 'Formula & Equation '//'E_'//CurrentTaxGP%TaxPowerVar%name
	    else
	      StatementStart = 'Formula'
	    end if
	    OutputString = trim(StatementStart)//' '//trim(TempString)
	    call WriteOneLineToTAB(OutputString)
! Mark the RATE (not the POWER) as endogenous
	    call MarkAsEndogenous(CurrentTaxGP%TaxRateChangeVar)
! The LHS
	    call CoeffVarRealToGP(CurrentTaxGP%TaxPowerCoeff, TempString)
	    OutputString = trim(TempString)//' = '

! Write LHS
	    call WriteOneLineToTAB('  '//OutputString)

! [03/06/04] If is condition, put this into an "IF" test around RHS
	    if(IOLineConditionExpression.ne.' ') then
	      OutputString = 'IF{ '//trim(IOLineConditionExpression)//', '
	    else
	      OutputString = ''
	    end if ! if(IOLineConditionExpression.ne.' ') then

! The RHS which is 1 - TaxRateCoeff [Output line] or 1 + TaxRateCoeff [Input line] 
	    call CoeffVarRealToGP(CurrentTaxGP%TaxRateCoeff, TempString)
	    OutputString = trim(OutputString)//' 1 '//PlusMinusChar//' '//trim(TempString)

! [03/06/04] If is condition, put closing "}" to end "IF" test around RHS, then ";"
	    if(IOLineConditionExpression.ne.' ') then
	        OutputString = trim(OutputString)//'} ;'
	    else
! Closing ";"
	        OutputString = trim(OutputString)//' ;'
	    end if

! Write RHS
	    call WriteOneLineToTAB('  '//OutputString)

! Formula (Initial) or "Formula & Equation" for TaxRevenueCoeff
! Formula keyword and quantifiers
	    call ArgToAllsGP(CurrentTaxGP%TaxRevenueCoeff%arg, TempString)
! Set up StatementStart
	    if(MixedTABFile) then
! Add the equation name here
	      StatementStart = 'Formula & Equation '//'E_'//CurrentTaxGP%TaxRevenueChangeVar%name
	    else
	      StatementStart = 'Formula (Initial)'
	    end if
	    OutputString = trim(StatementStart)//' '//trim(TempString)
	    call WriteOneLineToTAB(OutputString)
! Mark this as endogenous
	    call MarkAsEndogenous(CurrentTaxGP%TaxRevenueChangeVar)
! The LHS
	    call CoeffVarRealToGP(CurrentTaxGP%TaxRevenueCoeff, TempString)
	    OutputString = trim(TempString)//' = '
! Write LHS
	    call WriteOneLineToTAB('  '//OutputString)

! [03/06/04] If is condition, put this into an "IF" test around RHS
	    if(IOLineConditionExpression.ne.' ') then
	      OutputString = 'IF{ '//trim(IOLineConditionExpression)//', '
	    else
	      OutputString = ''
	    end if ! if(IOLineConditionExpression.ne.' ') then

! The RHS which is TaxRateCoeff * IOQFieldValueCoeff 
	    call CoeffVarRealToGP(CurrentTaxGP%TaxRateCoeff, TempString)
	    call CoeffVarRealToGP(CurrentNetputGP%IOQFieldValueCoeff, TempString2)
	    OutputString = trim(OutputString)//' '//trim(TempString)//' * '//trim(TempString2)

! [03/06/04] If is condition, put closing "}" to end "IF" test around RHS, then ";"
	    if(IOLineConditionExpression.ne.' ') then
	        OutputString = trim(OutputString)//'} ;'
	    else
! Closing ";"
	        OutputString = trim(OutputString)//' ;'
	    end if

! Write RHS
	    call WriteOneLineToTAB('  '//OutputString)

	    CurrentTaxNumber = CurrentTaxNumber + 1
	    CurrentTaxGP => CurrentTaxGP%next

!	   End "do while(CurrentTaxNumber.lt.CurrentNetputGP%NumTaxTypes)"
	  end do ! while

	  if(CurrentNetputGP%NumTaxTypes.ge.2) then

! Formula [(Always)] or "Formula & Equation" for TotalTaxPowerCoeff
!	  type (GPCoeffVarReal) :: TotalTaxPowerCoeff  !! power of tax (all tax types)

! Formula keyword and quantifiers
	    call ArgToAllsGP(CurrentNetputGP%TotalTaxPowerCoeff%arg, TempString)
! Set up StatementStart
	    if(MixedTABFile.and.CurrentNetputGP%NumTaxTypes.ge.2) then
! Add the equation name here
	      StatementStart = 'Formula & Equation '//'E_'//CurrentNetputGP%TotalTaxPowerVar%name
	    else
	      StatementStart = 'Formula'
	    end if
	    OutputString = trim(StatementStart)//' '//trim(TempString)
	    call WriteOneLineToTAB(OutputString)
! Mark this variable as endogenous
	    call MarkAsEndogenous(CurrentNetputGP%TotalTaxPowerVar)
! The LHS
	    call CoeffVarRealToGP(CurrentNetputGP%TotalTaxPowerCoeff, TempString)
	    OutputString = trim(TempString)//' = '
! Write this out
	    call WriteOneLineToTAB('  '//OutputString)

! [03/06/04] If is condition, put this into an "IF" test around RHS
	    if(IOLineConditionExpression.ne.' ') then
	      OutputString = 'IF{ '//trim(IOLineConditionExpression)//', '
	    else
	      OutputString = ''
	    end if ! if(IOLineConditionExpression.ne.' ') then

! The RHS which is 1 several [+/- TaxRateCoeff] terms
	    OutputString = trim(OutputString)//' 1'  

! Run through the taxes
	    CurrentTaxGP => CurrentNetputGP%FirstTaxGP
	    CurrentTaxNumber = 0
	    do while(CurrentTaxNumber.lt.CurrentNetputGP%NumTaxTypes)

!	  type (GPCoeffVarReal) :: TaxRateCoeff  !! tax rate
	      call CoeffVarRealToGP(CurrentTaxGP%TaxRateCoeff, TempString)
	      OutputString = trim(OutputString)//' '//PlusMinusChar//' '//TempString
	      if(LEN_TRIM(OutputString).gt.40) then
! Write this out
	        call WriteOneLineToTAB('  '//OutputString)
	        OutputString = ''
	      end if

	      CurrentTaxNumber = CurrentTaxNumber + 1
	      CurrentTaxGP => CurrentTaxGP%next

!	     End "do while(CurrentTaxNumber.lt.CurrentNetputGP%NumTaxTypes)"
	    end do ! while

! [03/06/04] If is condition, put closing "}" to end "IF" test around RHS, then ";"
	    if(IOLineConditionExpression.ne.' ') then
	        OutputString = trim(OutputString)//'} ;'
	    else
! Closing ";"
	        OutputString = trim(OutputString)//' ;'
	    end if

! Write this line to complete the formula
	    call WriteOneLineToTAB('  '//OutputString)

!	   End "if(CurrentNetputGP%NumTaxTypes.ge.2) then"
	  end if

!	       End "if(CurrentNetputGP%NumTaxTypes.gt.0) then"
	end if

	return
	end subroutine DoFormulasOneIOLine

	subroutine DoCostRevenueFormulasOneProdFunction(ThisFunctionGP)
! Input
	type (functionGP), pointer :: ThisFunctionGP
! Local
	type (netputGP), pointer :: ThisNetputGP
	type (taxGP), pointer :: ThisTaxGP
	integer :: NumFieldsToDo, NumFieldsDone, NSum, kpass
	type (GPCoeffVarReal) :: ThisGPCoeff, ThisGPCoeff2, LHSGPCoeff
	logical :: UseThis
	type (domain), pointer :: ThisSubDomain
	character(len=512) OutputString, TempString, TempString2, SumString, EndSumString
	integer :: CurrentTaxNumber
	character :: PlusOrMinusChar  ! '-' for outputs, '+' for inputs

	do kpass=1,2

! Outputs when KPASS=1
! Inputs when KPASS=2

!	  type (GPCoeffVarReal) :: TotalRevCoeff !! Marginal revenue as coefficient (relates to outputs)
!	  type (GPCoeffVarReal) :: TotalCostCoeff !! Marginal cost as coefficient (relates to inputs)

	  if(kpass.eq.1) then
	    LHSGPCoeff = ThisFunctionGP%TotalRevCoeff
	    NumFieldsToDo = ThisFunctionGP%NumOFields
	    PlusOrMinusChar = '-'
	  else if(kpass.eq.2) then
	    LHSGPCoeff = ThisFunctionGP%TotalCostCoeff
	    NumFieldsToDo = ThisFunctionGP%NumIFields
	    PlusOrMinusChar = '+'
	  end if

! Formula keyword and quantifiers
	  call ArgToAllsGP(LHSGPCoeff%arg, TempString)
	  OutputString = 'Formula '//trim(TempString)
	  call WriteOneLineToTAB(OutputString)
! The LHS
	  call CoeffVarRealToGP(LHSGPCoeff, TempString)
	  OutputString = trim(TempString)//' = '
! Write this out
	  call WriteOneLineToTAB('  '//OutputString)

! RHS.
! Must add tax revenue (for inputs) or subtract tax revenue (for outputs)

! Go through all the relevant (input or output) fields
	  NumFieldsDone = 0
	  ThisNetputGP => ThisFunctionGP%FirstNetputGP
	  do while(NumFieldsDone.lt.NumFieldsToDo)

! Only use this if is of correct (input or output) type
	    if(kpass.eq.1) then
	      UseThis = ThisNetputGP%netputMPSGE%f%label.eq.'o'
	    else if(kpass.eq.2) then
	      UseThis = ThisNetputGP%netputMPSGE%f%label.eq.'i'
	    end if

	    if(UseThis) then

! Revenue or Cost for this line
! If is a subdomain, need to sum over it

	      ThisSubdomain => ThisNetputGP%netputMPSGE%sd
	      call WriteSumsGP(ThisSubDomain, SumString, NSum)
	      call CoeffVarRealToGP(ThisNetputGP%IOQFieldValueCoeff, TempString)
! End the sums
	      call EndSumsGP(NSum, EndSumString)

	      if(ThisNetputGP%NumTaxTypes.eq.0) then

! No tax terms to consider
! Assemble and write it out for this output line
	        OutputString = trim(SumString)//' '//trim(TempString)//' '//trim(EndSumString)
		if(NumFieldsDone.le.NumFieldsToDo-2) then
!		     "+" at end before next term
		    OutputString = trim(OutputString)//' +'
		else
! semicolon to end the formula
		    OutputString = trim(OutputString)//' ;'
		end if

! Write this out
	        call WriteOneLineToTAB('    '//OutputString)

	      else if(ThisNetputGP%NumTaxTypes.gt.0) then

! Must consider the tax terms

! First output SUM and IOQFieldValueCoeff
	        OutputString = trim(SumString)//' '//trim(TempString)
	        call WriteOneLineToTAB('    '//OutputString)
		
! Run through the taxes
	        ThisTaxGP => ThisNetputGP%FirstTaxGP
	        CurrentTaxNumber = 0
	        do while(CurrentTaxNumber.lt.ThisNetputGP%NumTaxTypes)

	          call CoeffVarRealToGP(ThisTaxGP%TaxRevenueCoeff, TempString)
	          OutputString = PlusOrMinusChar//' '//TempString
		  if(CurrentTaxNumber.eq.ThisNetputGP%NumTaxTypes-1) then

!			This is the last term. Add the ENDSUMs here.
		    OutputString = trim (OutputString)//' '//EndSumString

		    if(NumFieldsDone.le.NumFieldsToDo-2) then
!		       "+" at end before next term
		      OutputString = trim(OutputString)//' +'
		    else
!		       ";" to end formula
		      OutputString = trim(OutputString)//' ;'
		    end if

		  end if


! Write this out
	          call WriteOneLineToTAB('        '//OutputString)

	          CurrentTaxNumber = CurrentTaxNumber + 1
	          ThisTaxGP => ThisTaxGP%next

!	         End "do while(CurrentTaxNumber.lt.ThisNetputGP%NumTaxTypes)"
	        end do ! while

!	       End "if(ThisNetputGP%NumTaxTypes.eq.0) then..else.."
	      end if

	      NumFieldsDone = NumFieldsDone + 1

!	     End "if(UseThis) then"
	    end if

	    ThisNetputGP => ThisNetputGP%next

!	   End "do while(NumFieldsDone.le.NumFieldsToDo)"
	  end do

	end do ! kpass=1,2

	return
	end subroutine DoCostRevenueFormulasOneProdFunction

	subroutine DoEquationsOneIOLine(CurrentFunctionGP, CurrentNetputGP, IOLineConditionExpression)
! Input
	type (functionGP), pointer :: CurrentFunctionGP
	type (netputGP), pointer :: CurrentNetputGP
	character(len=*), intent(in) :: IOLineConditionExpression
! Local
	character(len=512) OutputString, StatementStart, TempString, TempString2
	character(len=512) ExceptionString
	logical :: IsOLine, IsILine
	character PlusOrMinusChar
	character (len=255) :: ProdException
	type (GPCoeffMPSGE), pointer :: GPCoeffMPSGEHere

10005	format(a)

! Linear CES/CET equation associated with this i: or o: line
!  LHS is IOQFieldQuantityVar
	if(MixedTABFile) then
	  StatementStart = 'Equation (Linear)'
	else
	  StatementStart = 'Equation'
	end if
	OutputString = trim(StatementStart)//' E_'//CurrentNetputGP%IOQFieldQuantityVar%name
! Write this out
	call WriteOneLineToTAB(OutputString)
! Mark this variable as endogenous
	call MarkAsEndogenous(CurrentNetputGP%IOQFieldQuantityVar)

! Quantifiers and LHS and '='
	call ArgToAllsGP(CurrentNetputGP%IOQFieldQuantityVar%arg, TempString)
	call CoeffVarRealToGP(CurrentNetputGP%IOQFieldQuantityVar, TempString2)
	OutputString = trim(TempString)//' '//trim(TempString2)//' ='
! Write this out
	call WriteOneLineToTAB('  '//OutputString)

! [03/06/04] Now IOLineConditionExpression includes any condition on this
!   $prod block and any condition on thie i:/o: line.
	if(IOLineConditionExpression.ne.' ') then
	  call WriteOneLineToTAB('   IF{'//trim(IOLineConditionExpression)//',')
	end if ! if(ProdException.ne.' ') then

! RHS which is:
!  ActivityLevelVar + TElasticity * [<var>  - MargRevVar ]  for an o: line 
!  ActivityLevelVar - SElasticity * [<var>  - MargCostVar ]  for an i: line
! Above <var> is IOPriceVar if no taxes on this line, or is IOPriceIncTaxesVar if are some taxes  
	IsOLine = CurrentNetputGP%netputMPSGE%f%label.eq.'o'
	IsILine = CurrentNetputGP%netputMPSGE%f%label.eq.'i'

	if(IsOLine) then
	  PlusOrMinusChar = '+'
	else
	  PlusOrMinusChar = '-'
	end if

	call CoeffVarRealToGP(CurrentFunctionGP%ActivityLevelVar, OutputString)
	OutputString = trim(OutputString)//' '//PlusOrMinusChar
	if(IsOLine) then
	  if(CurrentFunctionGP%TElastPresent) then
	    call CoeffVarRealToGP(CurrentFunctionGP%TElasticity, TempString)
	  else
	    TempString = '0'
	  end if
	else
	  if(CurrentFunctionGP%SElastPresent) then
	    call CoeffVarRealToGP(CurrentFunctionGP%SElasticity, TempString)
	  else
	    TempString = '0'
	  end if
	end if
	OutputString = trim(OutputString)//' '//trim(TempString)//' * ['
	if(CurrentNetputGP%NumTaxTypes.gt.0) then
	  call CoeffVarRealToGP(CurrentNetputGP%IOPriceIncTaxesVar, TempString)
	else
	  call CoeffVarRealToGP(CurrentNetputGP%IOPriceVar, TempString)
	end if
	OutputString = trim(OutputString)//trim(TempString)//' -'
  
	if(IsOLine) then
	  call CoeffVarRealToGP(CurrentFunctionGP%MargRevVar, TempString)
	else
	  call CoeffVarRealToGP(CurrentFunctionGP%MargCostVar, TempString)
	end if
	OutputString = trim(OutputString)//' '//trim(TempString)//']'
	if(IOLineConditionExpression.ne.' ') then
! End if "IF{"
	  OutputString = trim(OutputString)//' }'
	end if

	OutputString = trim(OutputString)//' ;'
! Write this out
	call WriteOneLineToTAB('    '//OutputString)

! Taxes
! Need to do this for OLine or ILine if are taxes
! [06/04/04] This is now always done, and in the levels (see above)
!NOWLEV	if(CurrentNetputGP%NumTaxTypes.gt.0) then

! Equation for %-change in value of q: field. [This is only for o: lines]
! LHS is IOQFieldValueVar
! RHS is always Market Price (IOPriceVar) + IOQFieldQuantityVar. This is true for o: and i: fields

!NOWLEV	  if(MixedTABFile) then
!NOWLEV	    StatementStart = 'Equation (Linear)'
!NOWLEV	  else
!NOWLEV	    StatementStart = 'Equation'
!NOWLEV	  end if
!NOWLEV	  OutputString = trim(StatementStart)//' E_'//CurrentNetputGP%IOQFieldValueVar%name
! Write this out
!NOWLEV	  call WriteOneLineToTAB(OutputString)
! Mark this variable as endogenous
!NOWLEV	  call MarkAsEndogenous(CurrentNetputGP%IOQFieldValueVar)

! Quantifiers and LHS and '='
!NOWLEV	  call ArgToAllsGP(CurrentNetputGP%IOQFieldValueVar%arg, TempString)
!NOWLEV	  call CoeffVarRealToGP(CurrentNetputGP%IOQFieldValueVar, TempString2)
!NOWLEV	  OutputString = trim(TempString)//' '//trim(TempString2)//' ='
! Write this out
!NOWLEV	  call WriteOneLineToTAB('  '//OutputString)

! RHS
!NOWLEV	  call CoeffVarRealToGP(CurrentNetputGP%IOPriceVar, TempString)
!NOWLEV	  call CoeffVarRealToGP(CurrentNetputGP%IOQFieldQuantityVar, TempString2)
!NOWLEV	  OutputString = trim(TempString)//' + '//trim(TempString2)//' ;'

! Write this out
!NOWLEV	  call WriteOneLineToTAB('    '//OutputString)

!	 End "if(CurrentNetputGP%NumTaxTypes.gt.0) then"
!NOWLEV	end if 
	
	if(CurrentNetputGP%NumTaxTypes.gt.0) then

! Equation connecting price in i: or o: field with price including taxes and power of tax
! LHS is IOPriceIncTaxesVar
! RHS is IOPriceVar + <var> where
!    <var> is TotalTaxPowerVar if are 2 or more tax types, or
!    <var> is TaxPowerVar for the 1 tax if is just one tax type

	  if(MixedTABFile) then
	    StatementStart = 'Equation (Linear)'
	  else
	    StatementStart = 'Equation'
	  end if
	  OutputString = trim(StatementStart)//' E_'//CurrentNetputGP%IOPriceIncTaxesVar%name
! Write this out
	  call WriteOneLineToTAB(OutputString)
! Mark this variable as endogenous
	call MarkAsEndogenous(CurrentNetputGP%IOPriceIncTaxesVar)

! Quantifiers and LHS and '='
	  call ArgToAllsGP(CurrentNetputGP%IOPriceIncTaxesVar%arg, TempString)
	  call CoeffVarRealToGP(CurrentNetputGP%IOPriceIncTaxesVar, TempString2)
	  OutputString = trim(TempString)//' '//trim(TempString2)//' ='
! Write this out
	  call WriteOneLineToTAB('  '//OutputString)

! RHS
	  call CoeffVarRealToGP(CurrentNetputGP%IOPriceVar, TempString)
	  if(CurrentNetputGP%NumTaxTypes.ge.2) then
	    call CoeffVarRealToGP(CurrentNetputGP%TotalTaxPowerVar, TempString2)
	  else     !if(CurrentNetputGP%NumTaxTypes.eq.1) then
	    call CoeffVarRealToGP(CurrentNetputGP%FirstTaxGP%TaxPowerVar, TempString2)
	  end if
	  OutputString = trim(TempString)//' + '//trim(TempString2)//' ;'
! Write this out
	  call WriteOneLineToTAB('    '//OutputString)

!	 End "if(CurrentNetputGP%NumTaxTypes.gt.0) then"
	end if

!------------------------------------------------------------
! *** Next not necessary *** ??
!??	if(CurrentNetputGP%NumTaxTypes.gt.0) then

! Run through the taxes
!??	  CurrentTaxGP => CurrentNetputGP%FirstTaxGP
!??	  CurrentTaxNumber = 0
!??	  do while(CurrentTaxNumber.lt.CurrentNetputGP%NumTaxTypes)


!??	    CurrentTaxNumber = CurrentTaxNumber + 1
!??	    CurrentTaxGP => CurrentTaxGP%next

!??	  end do ! while

!	       End "if(CurrentNetputGP%NumTaxTypes.gt.0) then"
!??	end if
! ** End of not necessary? part ***
!------------------------------------------------------------

	end subroutine DoEquationsOneIOLine

	subroutine DoEquationsOneProdFunction(ThisFunctionGP)
! Input
	type (functionGP), pointer :: ThisFunctionGP
! Local
	character(len=512) OutputString, StatementStart, TempString, TempString2
	character(len=512) TempString3, TempString4, TempString5
	character(len=512) PriceVarString, SumString, EndSumString, TotalRevCostCoeffString
	character :: PlusOrMinusChar  ! '-' for outputs, '+' for inputs
	type (netputGP), pointer :: ThisNetputGP
	type (taxGP), pointer :: ThisTaxGP
	integer :: CurrentTaxNumber, NumFieldsDone, NumFieldsToDo, kpass, NSum
	logical :: UseThis
	type (domain), pointer :: ThisSubDomain
	character :: ISChar
	character (len=20) :: AssertString
	character (len=128) :: ThisLineAbbreviation
	type (GPCoeffVarReal) :: RelevantTaxPowerCoeff
! [04/05/04] WriteCondTotalRevCostEq tells if write equation for marginal
!   cost or revenue with IF[ tests
	logical, parameter :: WriteCondTotalRevCostEq=.true.
	character (len=2048) :: ProdException, ProdExceptionString, ThisExceptionString
	type(GPCoeffMPSGE), pointer :: GPCoeffMPSGEHere

! [10/05/04] If is exception on this $prod block, set up ProdExceptionString
!  which captures the exception. [Otherwise ProdExceptionString = ' ']
	ProdExceptionString = ' '
	ProdException = ThisFunctionGP%functionMPSGE%firstrecord%firstfield%condtn
	if(ProdException.ne.' ') then
! Translate the exception to GEMPACK. Complete logical expression if necessary
	  ProdExceptionString = ExpressionToGPSyntax2(ProdException, .true., 'NE 0', &
	    .false., GPCoeffMPSGEHere)
!	  write(*,*)'ProdExceptionString = ', trim(ProdExceptionString)
	end if ! if(ProdException.ne.' ') then

	do kpass=1,2

! Equation for marginal revenue (output lines) when KPASS=1
! Equation for marginal cost (input lines) when KPASS=2

! This is based on the code which writes the formulas for TotalRevenue and 
!   TotalCost in routine DoCostRevenueFormulasOneProdFunction

!	  type (GPCoeffVarReal) :: TotalRevCoeff !! Marginal revenue as coefficient (relates to outputs)
!	  type (GPCoeffVarReal) :: MargRevVar !! Marginal revenue as variable (relates to outputs)
!	  type (GPCoeffVarReal) :: TotalCostCoeff !! Total cost as coefficient (relates to inputs)
!	  type (GPCoeffVarReal) :: MargCostVar !! Marginal cost as variable (relates to inputs)

	  if(MixedTABFile) then
	    StatementStart = 'Equation (Linear)'
	  else
	    StatementStart = 'Equation'
	  end if
	  if(kpass.eq.1) then
	    OutputString = trim(StatementStart)//' E_'//ThisFunctionGP%MargRevVar%name
! Mark this variable as endogenous
	    call MarkAsEndogenous(ThisFunctionGP%MargRevVar)
	  else if(kpass.eq.2) then
	    OutputString = trim(StatementStart)//' E_'//ThisFunctionGP%MargCostVar%name
! Mark this variable as endogenous
	    call MarkAsEndogenous(ThisFunctionGP%MargCostVar)
	  end if
! Write this out
	  call WriteOneLineToTAB(OutputString)

! Quantifiers and LHS and '='
	  if(kpass.eq.1) then
	    call ArgToAllsGP(ThisFunctionGP%MargRevVar%arg, OutputString)
	    call CoeffVarRealToGP(ThisFunctionGP%TotalRevCoeff, TempString)
	    call CoeffVarRealToGP(ThisFunctionGP%MargRevVar, TempString2)
	  else if(kpass.eq.2) then
	    call ArgToAllsGP(ThisFunctionGP%MargCostVar%arg, OutputString)
	    call CoeffVarRealToGP(ThisFunctionGP%TotalCostCoeff, TempString)
	    call CoeffVarRealToGP(ThisFunctionGP%MargCostVar, TempString2)
	  end if

! [04/05/04] Next is not used at present
!WAS	  TotalRevCostCoeffString = TempString

!---------------------------------------------------------
! [04/05/04] If TotalRev/CostCoeff is zero, set MargRev/CostVar = 0
! Eg. (All,o_1,o)(All,s_1,s) 
!   IF[R_A(o_1,s_1) NE 0, R_A(o_1,s_1) * mr_a(o_1,s_1)] +
!     IF[R_A(o_1,s_1) EQ 0, mr_a(o_1,s_1)]  =
!     IF[R_A(o_1,s_1) NE 0, VS_A_PA(o_1,s_1) *pa(o_1,s_1)] ;
! instead of:
!  (All,o_1,o)(All,s_1,s) R_A(o_1,s_1) * mr_a(o_1,s_1) =
!     VS_A_PA(o_1,s_1) *pa(o_1,s_1) ;
 
	  if(.not.WriteCondTotalRevCostEq) then
! The old way
	    OutputString = trim(OutputString)//' '//trim(TempString)//' * '//trim(TempString2)//' ='
! Write this out
	    call WriteOneLineToTAB('  '//OutputString)

	  else ! if(WriteCondTotalRevCostEq) then
! The new way
	    if(OutputString.ne.' ') then
	      call WriteOneLineToTAB('  '//OutputString)
	    end if

! [10/05/04] Take account of any exception on this $prod block
!WAS	    OutputString = 'IF['//trim(TempString)//' NE 0, '// &
!WAS	      trim(TempString)//' * '//trim(TempString2)//'] +'
!WAS	    call WriteOneLineToTAB('   '//OutputString)
!WAS	    OutputString = 'IF['//trim(TempString)//' EQ 0, '//trim(TempString2)//'] ='
!WAS	    call WriteOneLineToTAB('    '//OutputString)

	    ThisExceptionString = trim(TempString)//' NE 0'
	    if(ProdExceptionString.ne.' ') then
	      ThisExceptionString = '{'//trim(ThisExceptionString)//'} AND {'// &
		trim(ProdExceptionString)//'}'
	    end if 
	    OutputString = 'IF['//trim(ThisExceptionString)//', '// &
	      trim(TempString)//' * '//trim(TempString2)//'] +'
	    call WriteOneLineToTAB('    '//OutputString)

	    OutputString = 'IF[ NOT['//trim(ThisExceptionString)//'], '//trim(TempString2)//'] = '
	    call WriteOneLineToTAB('     '//OutputString)

! Put test around RHS
!WAS	    OutputString = 'IF['//trim(TempString)//' NE 0, '
!WAS	    call WriteOneLineToTAB('   '//OutputString)
	    OutputString = 'IF['//trim(ThisExceptionString)//', '
	    call WriteOneLineToTAB('   '//OutputString)

	  end if ! if(.not.WriteCondTotalRevCostEq) then..else..
!---------------------------------------------------------

	  if(kpass.eq.1) then
	    NumFieldsToDo = ThisFunctionGP%NumOFields
	    PlusOrMinusChar = '-'
	  else if(kpass.eq.2) then
	    NumFieldsToDo = ThisFunctionGP%NumIFields
	    PlusOrMinusChar = '+'
	  end if

! RHS.
! Must add tax revenue (for inputs) or subtract tax revenue (for outputs)

! Go through all the relevant (input or output) fields
	  NumFieldsDone = 0
	  ThisNetputGP => ThisFunctionGP%FirstNetputGP
	  do while(NumFieldsDone.lt.NumFieldsToDo)

! Only use this if is of correct (input or output) type
	    if(kpass.eq.1) then
	      UseThis = ThisNetputGP%netputMPSGE%f%label.eq.'o'
	    else if(kpass.eq.2) then
	      UseThis = ThisNetputGP%netputMPSGE%f%label.eq.'i'
	    end if

	    if(UseThis) then

! Revenue or Cost for this line
! If is a subdomain, need to sum over it

	      ThisSubdomain => ThisNetputGP%netputMPSGE%sd
	      call WriteSumsGP(ThisSubDomain, SumString, NSum)
	      call CoeffVarRealToGP(ThisNetputGP%IOQFieldValueCoeff, TempString)
! End the sums
	      call EndSumsGP(NSum, EndSumString)

	      if(ThisNetputGP%NumTaxTypes.eq.0) then

! No tax terms to consider
! Relevant price variable is the price in the o: or i: field
	        call CoeffVarRealToGP(ThisNetputGP%IOPriceVar, PriceVarString)
! Assemble and write it out for this output line
	        OutputString = trim(SumString)//' '//trim(TempString)// &
			  ' *'//trim(PriceVarString)//' '//trim(EndSumString)
		if(NumFieldsDone.le.NumFieldsToDo-2) then
!		     "+" at end before next term
		    OutputString = trim(OutputString)//' +'
		else
! semicolon to end the equation
! [04/05/04] Now also "]" to end IF[ at start of RHS
!WAS		    OutputString = trim(OutputString)//' ;'
		    OutputString = trim(OutputString)//'] ;'
		end if

! Write this out
	        call WriteOneLineToTAB('    '//OutputString)

	      else if(ThisNetputGP%NumTaxTypes.gt.0) then

! Must consider the tax terms

! Relevant price variable is the price including taxes
	        call CoeffVarRealToGP(ThisNetputGP%IOPriceIncTaxesVar, PriceVarString)

! First output SUM, then opening "[" and then the IOQFieldValueCoeff
	        OutputString = trim(SumString)//' ['//trim(TempString)
	        call WriteOneLineToTAB('    '//OutputString)
		
! Run through the taxes
	        ThisTaxGP => ThisNetputGP%FirstTaxGP
	        CurrentTaxNumber = 0
	        do while(CurrentTaxNumber.lt.ThisNetputGP%NumTaxTypes)

	          call CoeffVarRealToGP(ThisTaxGP%TaxRevenueCoeff, TempString)
	          OutputString = PlusOrMinusChar//' '//TempString
		  if(CurrentTaxNumber.eq.ThisNetputGP%NumTaxTypes-1) then

!			This is the last term. Closing "]", then * PriceVar and the ENDSUMs here.
		    OutputString = trim (OutputString)//'] * '//trim(PriceVarString)//' '//EndSumString

		    if(NumFieldsDone.le.NumFieldsToDo-2) then
!		       "+" at end before next term
		      OutputString = trim(OutputString)//' +'
		    else
!		       ";" to end equation
! [04/05/04] Now also "]" to end IF[ at start of RHS
!WAS		      OutputString = trim(OutputString)//' ;'
		      OutputString = trim(OutputString)//'] ;'
		    end if

		  end if


! Write this out
	          call WriteOneLineToTAB('        '//OutputString)

	          CurrentTaxNumber = CurrentTaxNumber + 1
	          ThisTaxGP => ThisTaxGP%next

!	         End "do while(CurrentTaxNumber.lt.ThisNetputGP%NumTaxTypes)"
	        end do ! while

!	       End "if(ThisNetputGP%NumTaxTypes.eq.0) then..else.."
	      end if

	      NumFieldsDone = NumFieldsDone + 1

!	     End "if(UseThis) then"
	    end if

	    ThisNetputGP => ThisNetputGP%next

!	   End "do while(NumFieldsDone.le.NumFieldsToDo)"
	  end do

	end do ! kpass=1,2

! Zero profit equation
! [04/05/04] Write it as MargRevVar = MargCostVar.  [This is the same as
!  what had before since TotalRevCoeff equals TotalCostCoeff. But the
!   old version causes problems if TotalRevCoeff=TotalCostCoeff=0.]
!OLD LHS is TotalRevCoeff * MargRevVar 
!OLD RHS is TotalCostCoeff * MargCostVar

	if(MixedTABFile) then
	    StatementStart = 'Equation (Linear)'
	else
	    StatementStart = 'Equation'
	end if
! This determines the variable after $prod:
	OutputString = trim(StatementStart)//' E_'// &
	   trim(ThisFunctionGP%ActivityLevelVar%name)// &
	   ' # Zero profit condition for $prod:'// &
	     trim(ThisFunctionGP%functionMPSGE%firstrecord%firstfield%identtext)// &
	   ' #'
! Write this out
	call WriteOneLineToTAB(OutputString)
! Mark this variable as endogenous
	call MarkAsEndogenous(ThisFunctionGP%ActivityLevelVar)

! Quantifiers
	call ArgToAllsGP(ThisFunctionGP%MargRevVar%arg, OutputString)
! LHS
	call CoeffVarRealToGP(ThisFunctionGP%TotalRevCoeff, TempString)
	call CoeffVarRealToGP(ThisFunctionGP%MargRevVar, TempString2)
! RHS
	call CoeffVarRealToGP(ThisFunctionGP%TotalCostCoeff, TempString3)
	call CoeffVarRealToGP(ThisFunctionGP%MargCostVar, TempString4)

! [04/05/04] Suppress TotalRevCoeff and TotalCostCoeff
!WAS	OutputString = trim(OutputString)//' '//trim(TempString)//' * '// &
!WAS	  trim(TempString2)//' = '//trim(TempString3)//' * '//trim(TempString4)//' ;'

!NO	OutputString = trim(OutputString)//' '//trim(TempString2)// &
!NO		' = '//trim(TempString4)//' ;'
! Write this out
!NO	call WriteOneLineToTAB('  '//OutputString)

!----------------------------------------------------
! Suppress !NO above and try writing as :
!  IF(TotalRevCoeff NE 0, MargRevVar - MargCostVar) + IF(TotalRevCoeff EQ 0, ThisFunctionGP%ActivityLevelVar) = 0 ;
! Then, if TotalRevCoeff=0, this says that ThisFunctionGP%ActivityLevelVar = 0.
! Quantifiers
	if(OutputString.ne.' ') then
	  call WriteOneLineToTAB('   '//OutputString)
	end if

! [10/05/04] If is exception on this $prod block, take account of it.
	ThisExceptionString = trim(TempString)//' NE 0'
	if(ProdExceptionString.ne.' ') then
	  ThisExceptionString = '{'//trim(ThisExceptionString)//'} AND {'// &
		trim(ProdExceptionString)//'}'
	end if 
	OutputString = 'IF['//trim(ThisExceptionString)//', '//trim(TempString2)// &
		' - '//trim(TempString4)//'] +'
	call WriteOneLineToTAB('    '//OutputString)

	call CoeffVarRealToGP(ThisFunctionGP%ActivityLevelVar, TempString3)
	OutputString = 'IF[ NOT['//trim(ThisExceptionString)//'], '//trim(TempString3)//'] = 0 ;'
	call WriteOneLineToTAB('     '//OutputString)
!----------------------------------------------------

! Do slightly stricter assertion for intial data, less strict at other steps
	do kpass=1,2
! Do Assertion (Inital) when KPASS=1	
! Do Assertion (Always) when KPASS=2
	  if(kpass.eq.1) then
	    ISChar = 'I'
	  else if(kpass.eq.2) then
	    ISChar = 'S'
	  end if	
! Assertion that costs=revenue
	  if(kpass.eq.1) then
	    StatementStart = 'Assertion (Initial)'
	    AssertString = 'Initial data'
	  else if(kpass.eq.2) then
	    StatementStart = 'Assertion (Always)'
	    AssertString = 'At each step'
	  end if
! Write this out
	  call WriteOneLineToTAB(StatementStart)
! Assertion label
	  if(kpass.eq.1) then
	    OutputString =&
	 ' ! If this fails, the initial data is not balanced. !'
	    call WriteOneLineToTAB(OutputString)
	  else if(kpass.eq.2) then
	    OutputString =&
	 ' ! Use more than one subinterval if this Assertion fails - search ! '
	    call WriteOneLineToTAB(OutputString)
	    OutputString =&
	 ' !   for "subinterval" in the Command file.                       ! '
	    call WriteOneLineToTAB(OutputString)
	  end if
	  OutputString = ' # '//trim(AssertString)// &
	     '. Costs = revenue for $prod:'// &
	     trim(ThisFunctionGP%functionMPSGE%firstrecord%firstfield%identtext)// &
	   ' #'
! Write this out
	  call WriteOneLineToTAB(OutputString)
! Quantifiers
	  call ArgToAllsGP(ThisFunctionGP%MargRevVar%arg, OutputString)
! Write this out (if are any quantifiers)
	  if(OutputString.ne.' ') then
	    call WriteOneLineToTAB(OutputString)
	  end if
! LHS
	  call CoeffVarRealToGP(ThisFunctionGP%TotalRevCoeff, TempString)
! RHS
	  call CoeffVarRealToGP(ThisFunctionGP%TotalCostCoeff, TempString3)

! Cannot expect exact equality. So instead write it as
!  Revenue > 0.9999*Costs and Revenue < 1.0001*Costs
! [Equality]	OutputString = trim(OutputString)//' '//trim(TempString)// &
! [Equality]	  ' = '//trim(TempString3)//' ;'
! Use BALTOLI or BALTOLS
!	  OutputString = trim(OutputString)//' '//trim(TempString)// &
!	    ' GT 0.9999*'//trim(TempString3)//' AND '//trim(TempString)// &
!	    ' LT 1.0001*'//trim(TempString3)//' ;'
! [26/04/04] Use GE and LE to cater for the case where the values being comared
!   are both zero.
!WAS	  TempString4 = '['//trim(TempString)// ' GT (1-BALTOL'//ISChar//')*'//trim(TempString3)//'] AND'
	  TempString4 = '['//trim(TempString)// ' GE (1-BALTOL'//ISChar//')*'//trim(TempString3)//'] AND'
!	  write(*,*)'TempString4 = ', trim(TempString4)
	  TempString2 = '   '//trim(TempString4)
	  call WriteOneLineToTAB(TempString2)
!WAS	  TempString5 = '['//trim(TempString)// ' LT (1+BALTOL'//ISChar//')*'//trim(TempString3)//'] ;'
	  TempString5 = '['//trim(TempString)// ' LE (1+BALTOL'//ISChar//')*'//trim(TempString3)//'] ;'
!	  write(*,*)'TempString5 = ', trim(TempString5)
	  TempString2 = '   '//trim(TempString5)
	  call WriteOneLineToTAB(TempString2)
	end do ! do kpass=1,2

! If are any taxes, check that p: field is consistent with t: fields at the benchmark
! Do this for each o: or i: line in this function

! Go through all the relevant (input or output) fields
	NumFieldsDone = 0
	ThisNetputGP => ThisFunctionGP%FirstNetputGP
	NumFieldsToDo = ThisFunctionGP%NumOFields+ThisFunctionGP%NumIFields
	do while(NumFieldsDone.lt.NumFieldsToDo)

	  if(ThisNetputGP.NumTaxTypes.ge.1) then

! If NumTaxTypes.ge.2, need to compare TotalTaxPowerCoeff with value in p: field
! If NumTaxTypes=1, need to compare TaxPowerCoeff from the single TaxGP with value in p: field
	    if(ThisNetputGP.NumTaxTypes.ge.2) then
	      RelevantTaxPowerCoeff = ThisNetputGP%TotalTaxPowerCoeff
	    else ! if(ThisFunctionGP.NumTaxTypes.eq.1) then
	      RelevantTaxPowerCoeff = ThisNetputGP%FirstTaxGP%TaxPowerCoeff
	    end if

	    ThisLineAbbreviation = trim(ThisNetputGP%netputMPSGE%f%label)//':'//trim(ThisNetputGP%netputMPSGE%f%data)

! Assertion that RelevantTaxPowerCoeff = ThisNetputGP%PFieldCoeff
	    StatementStart = 'Assertion (Initial)'
	    AssertString = 'Initial data'
! Write this out
	    call WriteOneLineToTAB(StatementStart)
! Assertion label
	    OutputString =&
	 ' ! If this fails, the initial p: field data in line '//trim(ThisLineAbbreviation) 
	    call WriteOneLineToTAB(OutputString)
	    OutputString =&
	 '   is not consistent with the data in the t: fields in that line. !'
	    call WriteOneLineToTAB(OutputString)
	    OutputString = ' # '//trim(AssertString)// &
	     '. p: field consistent with t: fields in line '//trim(ThisLineAbbreviation) //' #'
! Write this out
	    call WriteOneLineToTAB(OutputString)
! Quantifiers
	    call ArgToAllsGP(RelevantTaxPowerCoeff%arg, OutputString)
! Write this out (if are any quantifiers)
	    if(OutputString.ne.' ') then
	      call WriteOneLineToTAB(OutputString)
	    end if
! LHS
	    call CoeffVarRealToGP(ThisNetputGP%PFieldCoeff, TempString)
! RHS
	    call CoeffVarRealToGP(RelevantTaxPowerCoeff, TempString3)

! Cannot expect exact equality. So instead write it as
!  LHS >= 0.9999*RHS and RHS <= 1.0001*LHS
! [Equality]	OutputString = trim(OutputString)//' '//trim(TempString)// &
! [Equality]	  ' = '//trim(TempString3)//' ;'

! Use BALTOLI
	    ISChar = 'I'

!	  OutputString = trim(OutputString)//' '//trim(TempString)// &
!	    ' GT 0.9999*'//trim(TempString3)//' AND '//trim(TempString)// &
!	    ' LT 1.0001*'//trim(TempString3)//' ;'
! [26/04/04] Use GE and LE to cater for the case where the values being comared
!   are both zero.
	    TempString4 = '['//trim(TempString)// ' GE (1-BALTOL'//ISChar//')*'//trim(TempString3)//'] AND'
!	    write(*,*)'TempString4 = ', trim(TempString4)
	    TempString2 = '   '//trim(TempString4)
	    call WriteOneLineToTAB(TempString2)
	    TempString5 = '['//trim(TempString)// ' LE (1+BALTOL'//ISChar//')*'//trim(TempString3)//'] ;'
!	    write(*,*)'TempString5 = ', trim(TempString5)
	    TempString2 = '   '//trim(TempString5)
	    call WriteOneLineToTAB(TempString2)
	  
	  end if ! if(ThisNetputGP.NumTaxTypes.ge.1) then

	  NumFieldsDone = NumFieldsDone + 1
	  ThisNetputGP => ThisNetputGP%next

!	 End "do while(NumFieldsDone.le.NumFieldsToDo)"
	end do

	return
	end subroutine DoEquationsOneProdFunction

	subroutine PrepareLabelInfoForTABFile(ThisLabellingInfo, OutputString)
! Puts "#" around label and truncates so OutputString has at most 79 characters
! Input
	character (len=*), intent(in) :: ThisLabellingInfo
! Output
	character (len=*), intent(out) :: OutputString
! Local
	character (len=73) :: LabelInfoUse
! Write the label
	LabelInfoUse = trim(ThisLabellingInfo)
! LabelInfoUse has at most 73 characters. Fit label info and ";" on one line
!  function adjustl removes any leading blanks and moves them to the end,
!    but it doesn't seem to work
	OutputString = ' # '//trim(adjustl(LabelInfoUse))//' # '

	return
	end subroutine PrepareLabelInfoForTABFile
	
	subroutine DoEquationsOneEndowmentLine(ThisEndowmentGP)
! Input
	type(endowmentGP), pointer :: ThisEndowmentGP
! Local
	character(len=512) OutputString, StatementStart, TempString, TempString2

!	write(*,*)'Beginning DoEquationsOneEndowmentLine'

	if(ThisEndowmentGP%HasRField) then
 
!	  type (GPCoeffVarReal) :: EndowQFieldQuantityCoeff  !! quantity (level) of each endowment q: field  
!	  type (GPCoeffVarReal) :: EndowQFieldQuantityVar  !! change in quantity of each endowment (q: field) 
!	  type (GPCoeffVarReal) :: EndowUnrationedQuantityCoeff  !! unrationed quantity of endowment (level)
!	  type (GPCoeffVarReal) :: EndowUnrationedQuantityVar  !! change in unrationed quantity of endowment

! If is rationing in this line, levels equation saying that 
!   EndowQFieldQuantityCoeff = EndowUnrationedQuantityCoeff * EndowRFieldCoeff (r: field levels variable)

	  if(MixedTABFile) then
	    StatementStart = 'Formula & Equation'
	  else
	    StatementStart = 'Equation'
	  end if
	  OutputString = trim(StatementStart)//' E_'//ThisEndowmentGP%EndowQFieldQuantityVar%name
! Write this out
	  call WriteOneLineToTAB(OutputString)
! Write label
	  call PrepareLabelInfoForTABFile( &
	    'Actual supply connected to unrationed quantity and rationing variable', OutputString)
	  call WriteOneLineToTAB(' '//OutputString)
! Mark this variable as endogenous
	  call MarkAsEndogenous(ThisEndowmentGP%EndowQFieldQuantityVar)

! LHS EndowQFieldQuantityCoeff 
! Quantifiers and LHS and '='
	  call ArgToAllsGP(ThisEndowmentGP%EndowQFieldQuantityCoeff%arg, OutputString)
	  call CoeffVarRealToGP(ThisEndowmentGP%EndowQFieldQuantityCoeff, TempString)
	  OutputString = trim(OutputString)//' '//trim(TempString)//' ='
! Write this out
	  call WriteOneLineToTAB('   '//OutputString)

! RHS. EndowUnrationedQuantityCoeff * EndowRFieldCoeff 
	  call CoeffVarRealToGP(ThisEndowmentGP%EndowUnrationedQuantityCoeff, TempString)
	  call CoeffVarRealToGP(ThisEndowmentGP%EndowRFieldCoeff, TempString2)
	  OutputString = trim(TempString)//' * '//trim(TempString2)//' ;'
! Write this out
	  call WriteOneLineToTAB('          '//OutputString)

	end if ! if(ThisEndowmentGP%HasRField) then

! Formula & Equation saying that EndowQFieldValueCoeff = EndowPriceCoeff * EndowQFieldQuantityCoeff
	StatementStart = 'Formula & Equation'
	OutputString = trim(StatementStart)//' E_'//ThisEndowmentGP%EndowQFieldValueVar%name
! Write this out
	call WriteOneLineToTAB(OutputString)
! Mark this variable as endogenous
	call MarkAsEndogenous(ThisEndowmentGP%EndowQFieldValueVar)
! Quantifiers and LHS and '='
	call ArgToAllsGP(ThisEndowmentGP%EndowQFieldValueCoeff%arg, TempString)
	call CoeffVarRealToGP(ThisEndowmentGP%EndowQFieldValueCoeff, TempString2)
	OutputString = trim(TempString)//' '//trim(TempString2)//' ='
! Write this out
	call WriteOneLineToTAB('  '//OutputString)

! RHS
	call CoeffVarRealToGP(ThisEndowmentGP%EndowPriceCoeff, TempString)
	call CoeffVarRealToGP(ThisEndowmentGP%EndowQFieldQuantityCoeff, TempString2)
	OutputString = trim(TempString)//' * '//trim(TempString2)//' ;'

! Write this out
	call WriteOneLineToTAB('    '//OutputString)



! {06/04/04] This is now always a levels equation - see earlier in this routine
! This writes the equation linking EndowQFieldValueVar with the associated
!   price EndowPriceVar and quantity EndowQFieldQuantityVar
!	  type (GPCoeffVarReal) :: EndowQFieldQuantityVar  !! %-change in quantity of each endowment  
!	  type (GPCoeffVarReal) :: EndowPriceVar    !! %-change in price (The price after e: at start of line)
!	  type (GPCoeffVarReal) :: EndowQFieldValueVar  !! %-change in value (level) of endowment

!LEV	if(MixedTABFile) then
!LEV	  StatementStart = 'Equation (Linear)'
!LEV	else
!LEV	  StatementStart = 'Equation'
!LEV	end if
!LEV	OutputString = trim(StatementStart)//' E_'//ThisEndowmentGP%EndowQFieldValueVar%name
! Write this out
!LEV	call WriteOneLineToTAB(OutputString)
! Write label
!LEV	call PrepareLabelInfoForTABFile( &
!LEV	  'Link '//trim(ThisEndowmentGP%EndowQFieldValueCoeff%name)//' [%-change is '// &
!LEV		trim(ThisEndowmentGP%EndowQFieldValueVar%name)//'] to its price and quantity', &
!LEV		OutputString)
!LEV	call WriteOneLineToTAB(' '//OutputString)
! Mark this variable as endogenous
!LEV	call MarkAsEndogenous(ThisEndowmentGP%EndowQFieldValueVar)

! Quantifiers and LHS and '='
!LEV	call ArgToAllsGP(ThisEndowmentGP%EndowQFieldValueVar%arg, OutputString)
!LEV	call CoeffVarRealToGP(ThisEndowmentGP%EndowQFieldValueVar, TempString)
!LEV	OutputString = trim(OutputString)//' '//trim(TempString)//' ='
! Write this out
!LEV	call WriteOneLineToTAB('   '//OutputString)

! RHS. EndowPriceVar + EndowQFieldQuantityVar
!LEV	call CoeffVarRealToGP(ThisEndowmentGP%EndowPriceVar, TempString)
!LEV	call CoeffVarRealToGP(ThisEndowmentGP%EndowQFieldQuantityVar, TempString2)
!LEV	OutputString = trim(TempString)//' + '//trim(TempString2)//' ;'
! Write this out
!LEV	call WriteOneLineToTAB('          '//OutputString)

!	write(*,*)'Ended DoEquationsOneEndowmentLine'

	return
	end subroutine DoEquationsOneEndowmentLine

	subroutine DoEquationsOneDemandFunction(ThisDemandFunctionGP)
! Input
	type(functionGP), pointer :: ThisDemandFunctionGP
! Local
	type (endowmentGP), pointer :: CurrentEndowmentGP
	type (domain), pointer :: ThisSubDomain
	type (functionGP), pointer :: CurrentFunctionGP
	type (netputGP), pointer :: CurrentNetputGP
	type (taxGP), pointer :: CurrentTaxGP
	type (taxlist), pointer :: CurrentTaxMPSGE
	integer :: NumEndowmentGPDone, NSum, NumTaxDone, NumNetputGPDone
	character(len=512) OutputString, StatementStart, TempString
	character(len=512) SumString, EndSumString, ThisConsumer
	integer :: NumTermsSoFar

	ThisConsumer = ThisDemandFunctionGP%functionMPSGE%firstrecord%firstfield%identtext

	NumTermsSoFar = 0

! Just one equation (a levels one if are doing mixed tab file).
! This adds up total income - value of endowments plus value of taxes
! This only done here properly for the MixedTABFile case.

	if(MixedTABFile) then
	  StatementStart = 'Formula & Equation'
	  OutputString = trim(StatementStart)//' E_'//ThisDemandFunctionGP%IncomeVar%name
! Mark this variable as endogenous
	  call MarkAsEndogenous(ThisDemandFunctionGP%IncomeVar)
	else
	    OutputString = 'Formula'
	end if
! Write this out
	call WriteOneLineToTAB(OutputString)
! Write label
	call PrepareLabelInfoForTABFile( &
		ThisDemandFunctionGP%TotalIncomeCoeff%labelinfo, OutputString)
	call WriteOneLineToTAB(' '//OutputString)

! Quantifiers and LHS and '='
	call ArgToAllsGP(ThisDemandFunctionGP%TotalIncomeCoeff%arg, OutputString)
	call CoeffVarRealToGP(ThisDemandFunctionGP%TotalIncomeCoeff, TempString)
	OutputString = trim(OutputString)//' '//trim(TempString)//' ='
! Write this out
	call WriteOneLineToTAB('  '//OutputString)

! RHS
! First go through the endowments (if any)
	if(ThisDemandFunctionGP%NumEFields.gt.0) then

	  CurrentEndowmentGP => ThisDemandFunctionGP%FirstEndowmentGP
	  NumEndowmentGPDone = 0
	  do while(NumEndowmentGPDone.lt.ThisDemandFunctionGP%NumEFields)

! Add value of these endowments
	    if(NumTermsSoFar.gt.0) then
	      StatementStart = '+'
	    else
	      StatementStart = ''
	    end if

! may involve SUM
! Example taken from FISCFED.
! $demand:state(r,eqx)
!        e:pgrant(eqx)    q:t0(r,eqx)         r:trn(r,eqx)
! Here the equation says (all,r)(all,eqx) VI(r,eqx) = QFieldValueCoeff(r,eqx) - that is, no sums
! In general, need to sum over any sets in domain of QFieldValueCoeff which are not in domain of VI.
! That is, sum over the sets in the subdomain %sd of this endowment

! may involve SUM
	    ThisSubdomain => CurrentEndowmentGP%endowmentMPSGE%sd
	    call WriteSumsGP(ThisSubDomain, SumString, NSum)

	    call CoeffVarRealToGP(CurrentEndowmentGP%EndowQFieldValueCoeff, TempString)
! End the sums
	    call EndSumsGP(NSum, EndSumString)
	    OutputString = trim(StatementStart)//' '//trim(SumString)// &
		' '//trim(TempString)//' '//EndSumString 
! Write this out
	    call WriteOneLineToTAB('    '//OutputString)
! Increment NumTermsSoFar
	    NumTermsSoFar = NumTermsSoFar + 1

	    CurrentEndowmentGP => CurrentEndowmentGP%next
	    NumEndowmentGPDone = NumEndowmentGPDone + 1
	  end do ! while

!	 End "if(ThisDemandFunction%NumEFields.gt.0) then"
	end if

! Now add any tax revenue accruing to this agent
! Run through the $prod functionGPs
	CurrentFunctionGP => FunctionGPList
	do while(associated(CurrentFunctionGP))
	  if(CurrentFunctionGP%IsProdFunctionGP) then

! Run through the o: and i: lines for this functionGP
	    CurrentNetputGP => CurrentFunctionGP%FirstNetputGP
	    NumNetputGPDone = 0
	    do while(NumNetputGPDone.lt.CurrentFunctionGP.NumIFields+CurrentFunctionGP.NumOFields)

	      if(CurrentNetputGP%NumTaxTypes.gt.0) then
	        CurrentTaxGP => CurrentNetputGP%FirstTaxGP
	        CurrentTaxMPSGE => CurrentTaxGP%taxlistMPSGE
	        NumTaxDone = 0
	        do while(NumTaxDone.lt.CurrentNetputGP%NumTaxTypes)

		  if (EqualStringsIgnoreCase(ThisConsumer, CurrentTaxMPSGE%a%ident%name)) then
! This tax revenue goes to ThisConsumer. Add tax to revenue

! SUM over relevant sets
!NO	            ThisSubdomain => CurrentTaxGP%TaxRevenueCoeff%arg
!NO	            call WriteSumsGP(ThisSubDomain, SumString, NSum)

! In general, need to sum over any sets in domain of CurrentTaxGP%TaxRevenueCoeff which are not in domain of TotalIncomeCoeff.

	            if(.not.IsSubdomainIgnoreOrder(ThisDemandFunctionGP%TotalIncomeCoeff%arg, &
 					CurrentTaxGP%TaxRevenueCoeff%arg)) then
!		      This is an error
		      call ErrorStop('$demand: TotalIncomeCoeff domain is not a subset of tax revenue arguments')
	            end if

! Sum over all sets in CurrentTaxGP%TaxRevenueCoeff which are not arguments of TotalIncomeCoeff
! Use subroutine findsubdomain to work this out.
!       subroutine findsubdomain(d1,d2,subdomain) determines those elements of d1 which are not in d2.

	    	    call findsubdomain(CurrentTaxGP%TaxRevenueCoeff%arg, ThisDemandFunctionGP%TotalIncomeCoeff%arg, &
 			ThisSubdomain)
            	    call WriteSumsGP(ThisSubDomain, SumString, NSum)

	            call CoeffVarRealToGP(CurrentTaxGP%TaxRevenueCoeff, TempString)
! End the sums
	            call EndSumsGP(NSum, EndSumString)
	            if(NumTermsSoFar.gt.0) then
	              StatementStart = '+'
	            else
	              StatementStart = ''
	            end if
	            OutputString = trim(StatementStart)//' '//trim(SumString)// &
		      ' '//trim(TempString)//' '//EndSumString 
! Write this out
	            call WriteOneLineToTAB('    '//OutputString)
! Increment NumTermsSoFar
	    	    NumTermsSoFar = NumTermsSoFar + 1

	          end if

	          NumTaxDone = NumTaxDone + 1
	          CurrentTaxGP => CurrentTaxGP%next
	          CurrentTaxMPSGE => CurrentTaxMPSGE%next
	        end do ! while

!	       End "if(CurrentNetputGP%NumTaxTypes.gt.0) then"
	      end if

	      NumNetputGPDone = NumNetputGPDone + 1
	      CurrentNetputGP => CurrentNetputGP%next
	    end do  ! while(NumNetputGPDone.lt.CurrentFunctionGP.NumIFields+CurrentFunctionGP.NumOFields)

!	   End "if(CurrentFunctionGP%IsProdFunctionGP) then"
	  end if

	  CurrentFunctionGP => CurrentFunctionGP%next
	end do ! CurrentFunction

! End this statement
	call WriteOneLineToTAB('       ;')

	return
	end subroutine DoEquationsOneDemandFunction

	subroutine WriteStartMarketClearEquation( &
	  InDField, ThisIsWalrasEq, WriteLinearMktClear, UseIndexStack, &
	  CurrentSymbol, WalrasSlackVar, WalrasSlackCoeff, &
	  DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
	  OutputStringAlls)
! [06/05/04] Extracted from routine DoMarketClearingEquations where similar code
!  was executed several times
! This writes the Equation statement, equation name, equation label and quantifiers
! It also puts term walrasslack = (ie LHS) when  this is Walras Equation
! Input
	logical, intent(in) :: InDField, ThisIsWalrasEq, WriteLinearMktClear, UseIndexStack
	type (symbol), pointer :: CurrentSymbol
	type (GPCoeffVarReal) :: WalrasSlackVar, WalrasSlackCoeff
	integer, intent(in) :: DimIndexStack
	integer, intent(in) :: TopIndexStack
	character(len=*), intent(in) :: IndexStackSets(DimIndexStack)
	character(len=*), intent(in) :: IndexStackIndexes(DimIndexStack)
	character (len=*), intent(in) :: OutputStringAlls
! Local
	character(len=512) StatementStart, OutputString, TempString

! Blank line(s) and  then comment line to start with
	call WriteOneLineToTAB(' ')
	if(ThisIsWalrasEq) then
	  OutputString = '! [Omitting market clearing equation for '//trim(CurrentSymbol%name)
	  call WriteOneLineToTAB(OutputString)
	  OutputString = '   to take account of Walras law.] !'
	  call WriteOneLineToTAB(OutputString)
	else
	  OutputString = '! Market clearing for '//trim(CurrentSymbol%name)//' !'
	  call WriteOneLineToTAB(OutputString)
	end if
	call WriteOneLineToTAB(' ')

	      if(MixedTABFile) then
	       if(WriteLinearMktClear.or.InDField) then
	        StatementStart = 'Equation (Linear)'
	       else if(ThisIsWalrasEq.and. .not.InDField) then
! Formula & Equation for WALRAWSSLACK
	        StatementStart = 'Formula & Equation'
	       else
	        StatementStart = 'Equation (Levels)'
	       end if
	      else
	       StatementStart = 'Equation'
	      end if
! Write the equation differently if this is WalrasEq
	      if(.not.ThisIsWalrasEq) then
	        OutputString = trim(StatementStart)//' E_'//CurrentSymbol%name
	      else if(ThisIsWalrasEq) then
	        OutputString = trim(StatementStart)//' E_'//WalrasSlackVar%name
	      end if
! Write this out
!	    write(*,*)'Beginning: '//trim(OutputString)
	      call WriteOneLineToTAB(OutputString)
! Write label
	      if(.not.ThisIsWalrasEq) then
	        call PrepareLabelInfoForTABFile( &
	          'Market clearing equation for commodity '//trim(CurrentSymbol%name), &
		    OutputString)
	      else if(ThisIsWalrasEq) then
	        call PrepareLabelInfoForTABFile(WalrasSlackVar%labelinfo, OutputString)
	      end if
	      call WriteOneLineToTAB(' '//OutputString)

! Write Quantifiers
	    if(OutputStringAlls.ne.' ') then
	      call WriteOneLineToTAB(' '//OutputStringAlls)
	    end if


	    if(ThisIsWalrasEq) then

! WalrasEq case. If the omitted equation is "a+b=c+d", we are writing it as
!    "walrasslack = -a-b+c+d"
! Write the LHS and "=" here

	      if(InDField) then
! Linear equation - use the linear variable on LHS
	        call CoeffVarRealToGP(WalrasSlackVar, TempString)
	      else
! Levels equation - use the levels variable on LHS
	        call CoeffVarRealToGP(WalrasSlackCoeff, TempString)
	      end if

	      call WriteOneLineToTAB(' '//trim(TempString)//' =')

	    end if ! if(ThisIsWalrasEq) then

	return
	end subroutine WriteStartMarketClearEquation


	subroutine DoMarketClearingEquations

! Local
	type (endowmentGP), pointer :: CurrentEndowmentGP
	type (domain), pointer :: ThisSubDomain
	type (functionGP), pointer :: CurrentFunctionGP
	type (netputGP), pointer :: CurrentNetputGP
	integer :: kpass, NumTermsSoFar, NSum, NumNetputGPDone, NumEndowmentGPDone
	character(len=1024) OutputString, StatementStart, TempString, OutputStringAlls
	character(len=1024) SinkSourceOutputStringAlls
	character(len=1024) SumString, EndSumString, TempString2, TempString3, TempString4
	character(len=1024) ConditionalSumString, TempString5
	type (GPCoeffVarReal) :: CurrentSectorPriceVar
	type (symbol), pointer :: CurrentSymbol
	type (field), pointer :: CurrentDemand
	type (domain), pointer :: FoundArgs, DFieldDemandArgs
	logical :: UseThis, InDField, ProdFound, FoundWalrasEq, Found, ThisIsWalrasEq
	integer :: NumProdFound
	character :: FoundUserSystemType
	character (len=3) :: ch3
! If find commodity in d: field of a $demand function, 
!  record IncomeVar, TotalIncomeCoeff from this $demand function.
! Also record ActivityLevelVar from the $prod: block containing this commodity in a o: line
	type (GPCoeffVarReal) :: IncomeVarDField !! %-change in value of income for this agent
	type (GPCoeffVarReal) :: TotalIncomeCoeffDField !! Total income for this consumer
	type (GPCoeffVarReal) :: ActivityLevelVarDField !! Activity level in the (unique?) $prod block
			! in which this appears in an o: field
	type (GPCoeffVarReal) :: ThisEndowValueCoeff, ThisEndowQuantityVar, ThisEndowQuantityCoeff, ThisEndowPriceCoeff
	type (GPCoeffVarReal) :: ThisPriceCoeff, ThisPriceVar
! [08/04/04] Must put SUM indexes and sets on IndexStack. So have no simple estimate of mas size neeeded
!  in advance. Now use large dimension DimIndexStack and don't try to allocate at run time.
!WAS	character(len=llst), allocatable, dimension(:) :: IndexStackSets
!WAS	character(len=llindex), allocatable, dimension(:) :: IndexStackIndexes
	integer, parameter :: DimIndexStack=200
	integer :: TopIndexStack
	character(len=llst) :: IndexStackSets(DimIndexStack)
	character(len=llindex) :: IndexStackIndexes(DimIndexStack)
	logical :: UseIndexStack
	type(domain), pointer :: CurrentLineDomain, CurrentDeclaredDomain, ThisDLineArg
	integer :: CurrentArgNumber, assno
! For assertion that total value of supply equals total value of demand

!VALUE	type (GPCoeffVarReal) :: TotalValueCoeff, TotalValueDemandCoeff, TotalValueSupplyCoeff
	type (GPCoeffVarReal) :: TotalValueCoeff, TotalValueDemandCoeff, TotalValueSupplyCoeff

	type (GPCoeffVarReal) :: TotalQuantityCoeff, TotalQuantityDemandCoeff, TotalQuantitySupplyCoeff
	type (GPCoeffVarReal) :: TotalQuantityVar, TotalQuantityDemandVar, TotalQuantitySupplyVar
	character :: DemandSupplyChar, ISChar
	character (len=20) :: AssertString
	logical :: PriceAtStartOfThisLine, EquationStartWritten

	logical :: WriteLinearMktClear

! [05/05/04] Now write market clear  
! with extra IF term which sets %%-change in activity level to zero if total
!  value of supply is zero (or negative) 
	logical, parameter :: WriteConditionalMarketClear=.true.
	integer :: KPassStart, KPassEnd, len1
	logical :: IsConditionOnLHSOfEquation
	character (len=2048) :: PriceExceptionStringGAMS, PriceExceptionString, ThisExceptionString
	type(GPCoeffMPSGE), pointer :: GPCoeffMPSGEHere

	character (len=3) :: CompString
	write(*,*)'Beginning Market clearing equations'

! [07/04/04] By default write the market clearing equations involving SUMs as levels equations when are
!  writing a mixed TAB file.
! If want them to be written as linearized equations in that case, set WriteLinearMktClear true.
! [Always write the market clearing equations involving income for $consumers as linearized equations.]
	if(MixedTABFile) then
	  WriteLinearMktClear = .false.  ! Set true if want linearized market clearing equations written
	else
	  WriteLinearMktClear = .true.
	end if


! Run through the commodities (the prices). For each one, there is a single
!  linear equation which says demand = supply. 
!  See which $prod and which $demand functions each one is in. 
! Supplies are in o: lines of $prod functions and in e: lines or $demand functions
! Supplies are in i: lines of $prod functions and in d: lines or $demand functions


	FoundWalrasEq = .false.
! WalrasNumeraireString is used in Command file. Initialise it in case do not find the Walras equation
	WalrasNumeraireString = ' '
	TopIndexStack = 0

! [31/03/04] UseIndexStack (or something similar) is necessary in some cases,
!  though not in all. For the present, always do that. Later may test and
!  only do it when required.
!	UseIndexStack = .false. 
	UseIndexStack = .true. 

! Write headings for this section of the TAB file
	call WriteOneLineToTAB(' ')
	OutputString = '![[! Market clearing equations (one for each $commodity)'
	call WriteOneLineToTAB(OutputString)
	OutputString = &
	    '  But, noting Walras law, one of these equations must be omitted !]]!'
	call WriteOneLineToTAB(OutputString)

! Go through the commodities. Find them by going through idlist.

	CurrentSymbol => idlist
	do while(associated(CurrentSymbol))
	  if(CurrentSymbol%type.eq.'commodity') then

!  Re-initialize 'pre' messages again at start of each price
	    call InitializeMessages('pre',0)
	    Messages%PreLine(1)='Doing market clearing for '//trim(CurrentSymbol%name)
! Echo this function so user sees progress (will echo each block twice, when BigCoeffPass=1 and 2
	    if(EchoMainProgressGP) then
	      write(*,'(2x,a)') trim(Messages%PreLine(1))
	    end if

	    EquationStartWritten = .false.
	    ThisIsWalrasEq = .false.
	    IsConditionOnLHSOfEquation = .false.

! Set up GPCoeffVarReal to denote ThisPriceCoeff - the levels value corresponding
!   to the price for which are doing market clearing
	              call InitializeGPCoeffVarReal('c', ThisPriceCoeff)
! [05/06/04] Use function GPLevelsName
!WAS		      ThisPriceCoeff%name = trim(CurrentSymbol%name)//'_L'
!WAS		      call upper(ThisPriceCoeff%name)  ! make name upper case
		      ThisPriceCoeff%name = GPLevelsName(CurrentSymbol%name)
		      ThisPriceCoeff%arg => CurrentSymbol%arg
! Don't need to set up any more of ThisPriceCoeff

! Set up GPCoeffVarReal to denote ThisPriceVar - the linear variable corresponding
!   to the price for which are doing market clearing
! Later will use ThisPriceVar in call to MarkAsEndogenous (except when this is Walras Eq)
	              call InitializeGPCoeffVarReal('v', ThisPriceVar)
		      ThisPriceVar%name = trim(CurrentSymbol%name)
		      call lower(ThisPriceVar%name)  ! make name lower case
		      ThisPriceVar%arg => CurrentSymbol%arg
! Don't need to set up any more of ThisPriceVar

! Can we omit this to satisfy Walras law?
! For the present, omit first one which has no arguments (if is one)
	    if(.not.FoundWalrasEq) then
	      call IsNameInGPNameList(CurrentSymbol%name, Found, FoundUserSystemType, FoundArgs)
	      if(Found) then
		if(.not.associated(FoundArgs)) then
! Omit this to satisfy Walras law
		  FoundWalrasEq = .true.
		  ThisIsWalrasEq = .true.
! WalrasNumeraireString is used in Command file
	          WalrasNumeraireString = CurrentSymbol%name

!! Comments before this equation now written in routine WriteStartMarketClearEquation
!!	          call WriteOneLineToTAB(' ')
!!		  OutputString = '! [Omitting market clearing equation for '//trim(CurrentSymbol%name)
!!	          call WriteOneLineToTAB(OutputString)
!!		  OutputString = '   to take account of Walras law.] !'
!!	          call WriteOneLineToTAB(OutputString)
		end if ! if(.not.associated(FoundArgs)) then
	      end if ! if(Found) then
	    end if ! if(.not.FoundWalrasEq) then

! Write Market clearing equation for this commodity.

	    InDField = .false.

! [08/06/04] Do not need to know if this commodity appears in
!  a d: field, so remove the code checking this and simply
!  leave InDField false.

	    if(ThisIsWalrasEq) then
! Declare WalrasSlackVar and WalrasSlackCoeff (if needed)
! WalrasSlack equation is a levels equation.
! Declare both WalrasSlackCoeff and WalrasSlackVar
! WalrasSlackCoeff
	        call InitializeGPCoeffVarReal('c', WalrasSlackCoeff)
	        nullify(WalrasSlackCoeff%arg)
	        WalrasSlackCoeff%name = ConstructGPName('c', 's', WalrasSlackVar%arg, &
					'WALRASSLACK', ' ')
	        call upper(WalrasSlackCoeff%name)   ! Convert name to upper case
	        WalrasSlackCoeff%labelinfo = 'Check of omitted market clearing equation. Result should be zero.'
	        WalrasSlackCoeff%IsGE0  = .false.
! WalrasSlackVar
	        call InitializeGPCoeffVarReal('v', WalrasSlackVar)
	        nullify(WalrasSlackVar%arg)
	        WalrasSlackVar%name = ConstructGPName('v', 's', WalrasSlackVar%arg, &
					'c_WALRASSLACK', ' ')
	        call lower(WalrasSlackVar%name)   ! Convert name to lower case
	        WalrasSlackVar%labelinfo = 'Check of omitted market clearing equation. Result should be zero.'
	        WalrasSlackVar%VarType = 'c'  ! Is a change variable
! Blank line in TAB file before this declaration
	        call WriteOneLineToTAB(' ')
! Declare as a levels variable
		call DeclareGPLevelsVar(WalrasSlackCoeff, WalrasSlackVar)
	    end if


! Quantifiers - always range over sets this price was declared with in $commodity section
! [Checked much earlier in the MPSGE module that the price at the start of the relevant
!   d:, e:, i: or o: field was declared appropriately in $commodity section.]
! [31/03/04] Need to get special all indexes since the expressions can be
!   complicated when sets over which price ranges in field is different from
!   sets over which it is declared in the $commodities part
!
	    if(.not.UseIndexStack) then  
	      call ArgToAllsGP(CurrentSymbol%arg, OutputStringAlls)
	    else if(UseIndexStack) then
! no longer allocate
!WAS	      DimIndexStack = GetArgDim(CurrentSymbol%arg)
! If these arrays are allocated, first deallocate them
!WAS	      if(allocated(IndexStackSets)) then
!WAS	        deallocate(IndexStackSets, IndexStackIndexes)
!WAS	      end if
!  Allocate IndexStackSets and IndexStackIndexes arrays
!WAS	      allocate(IndexStackSets(DimIndexStack), IndexStackIndexes(DimIndexStack))
! Don't use index stack if InDField is true. That is because the market clearing equation just
!  says something like "(all,h_1,h) income(h_1)=quantity(h_1)+price(h_1)"
	      if(InDField) then
! [18/04/04] Have possible conflict between CurrentSymbol%arg and those of the relevant income, price
!		and quantity variables. 
! For example (see JOINTH2.MGE)
!  ra(h) in $consumers: section, $demand:ra(g) containing d:pu(g) and find 
!  o:pu(h) in $prod:u(h).
! To remove such problems, use the arguments in relevant $demand block. Call these
!    DFieldDemandArgs and use them in the quantifiers and when writing the different
!    variables in the equation.
		DFieldDemandArgs => TotalIncomeCoeffDField%arg 
!WAS	        call ArgToAllsGP(CurrentSymbol%arg, OutputStringAlls)
	        call ArgToAllsGP(DFieldDemandArgs, OutputStringAlls)
	      else
	        call ArgToAllsGPUseIndexStack(CurrentSymbol%arg, DimIndexStack, &
		  OutputStringAlls, TopIndexStack, IndexStackSets, IndexStackIndexes)
	      end if
	    end if


! go through the $prod and $demand functions.
! Do Total Value of demand when KPASS=3
! Do Total Value of supply when KPASS=4
	

	    if(WriteConditionalMarketClear) then
! [08/06/04] Just need KPASS=3 and 4. No Others. [Write market clearing equations at end of KPASS=4.]
		KPassStart=3
		KPassEnd=4
	    else
		KPassStart=1
		KPassEnd=4
	    end if

	    do kpass=KPassStart,KPassEnd
!	    write(*,*)' KPASS=', kpass

! [08/06/04] Change to total quantity of demand or supply
! When KPASS=3,4 make up name of Coefficient to hold total value of demand or supply
	      if(kpass.eq.3.or.kpass.eq.4) then

! First a comment
	        if(kpass.eq.3) then
	          call WriteOneLineToTAB(' ')
!VALUE	          OutputString = '! Calculation of Total Value of Demand and Supply for '//trim(CurrentSymbol%name)//' !'
	          OutputString = '! Calculation of Total Quantity of Demand and Supply for '//trim(CurrentSymbol%name)//' !'
	          call WriteOneLineToTAB(OutputString)
		end if

!VALUE	        call InitializeGPCoeffVarReal('c', TotalValueCoeff)
!VALUE		if(kpass.eq.3) then
!VALUE		  DemandSupplyChar = 'd'
!VALUE		else
!VALUE		  DemandSupplyChar = 's'
!VALUE		end if
!VALUE	        TotalValueCoeff%name = ConstructGPName('c', 's', CurrentSymbol%arg, &
!VALUE					'TV'//DemandSupplyChar//'_'//trim(CurrentSymbol%name), 'TV'//DemandSupplyChar)
!VALUE	        call upper(TotalValueCoeff%name)   ! Convert name to upper case
!VALUE	        TotalValueCoeff%arg => CurrentSymbol%arg
!VALUE		if(kpass.eq.3) then 
!VALUE	          TotalValueCoeff%labelinfo = 'Total value of demand for commodity '//CurrentSymbol%name
!VALUE		else if(kpass.eq.4) then
!VALUE	          TotalValueCoeff%labelinfo = 'Total value of supply for commodity '//CurrentSymbol%name
!VALUE		end if
!VALUE		if(kpass.eq.3) then
!VALUE		  TotalValueDemandCoeff = TotalValueCoeff
!VALUE		else if(kpass.eq.4) then
!VALUE		  TotalValueSupplyCoeff = TotalValueCoeff
!VALUE		end if
! Declare this
!VALUE	        call DeclareGPCoeffVar(TotalValueCoeff)

! [08/06/04] TotalQuantityCoeff is a levels variable
		if(kpass.eq.3) then
		  DemandSupplyChar = 'd'
		else
		  DemandSupplyChar = 's'
		end if
	        call InitializeGPCoeffVarReal('c', TotalQuantityCoeff)
	        TotalQuantityCoeff%name = ConstructGPName('c', 's', CurrentSymbol%arg, &
					'TQ'//DemandSupplyChar//'_'//trim(CurrentSymbol%name), 'TQ'//DemandSupplyChar)
	        call upper(TotalQuantityCoeff%name)   ! Convert name to upper case
	        TotalQuantityCoeff%arg => CurrentSymbol%arg
		if(kpass.eq.3) then 
	          TotalQuantityCoeff%labelinfo = 'Total quantity of demand for commodity '//CurrentSymbol%name
		else if(kpass.eq.4) then
	          TotalQuantityCoeff%labelinfo = 'Total quantity of supply for commodity '//CurrentSymbol%name
		end if
		if(kpass.eq.3) then
		  TotalQuantityDemandCoeff = TotalQuantityCoeff
		else if(kpass.eq.4) then
		  TotalQuantitySupplyCoeff = TotalQuantityCoeff
		end if

	        call InitializeGPCoeffVarReal('v', TotalQuantityVar)
!NO Add "p_" at start for the variable
! [08/06/04] Make it a change variable because of problems that occur in the
!  linearised version of this equation when use change differentiation if the
!  total quantity demanded or supplied is zero.
		TotalQuantityVar%name = ConstructGPName('v', 's', CurrentSymbol%arg, 'c_'//trim(TotalQuantityCoeff%name), ' ')
	        call lower(TotalQuantityVar%name)   ! Convert name to lower case
	        TotalQuantityVar%arg => CurrentSymbol%arg
	        TotalQuantityVar%VarType = 'c' ! Change variable
		if(kpass.eq.3) then 
	          TotalQuantityVar%labelinfo = '%-change in total quantity of demand for commodity '//CurrentSymbol%name
		else if(kpass.eq.4) then
	          TotalQuantityVar%labelinfo = '%-change in total quantity of supply for commodity '//CurrentSymbol%name
		end if
		if(kpass.eq.3) then
		  TotalQuantityDemandVar = TotalQuantityVar
		else if(kpass.eq.4) then
		  TotalQuantitySupplyVar = TotalQuantityVar
		end if
! Declare these
	        call DeclareGPLevelsVar(TotalQuantityCoeff, TotalQuantityVar)

!VALUE Start a formula(always) for this coeff
!VALUE		StatementStart = 'Formula (Always)'
! Start a formula & Equation for this coeff
		StatementStart = 'Formula & Equation '//'E_'//trim(TotalQuantityCoeff%name)
! Write this out
!	        write(*,*)'Beginning: '//trim(StatementStart)
	        call WriteOneLineToTAB(StatementStart)
! Labelling info for this formula
!VALUE	        call PrepareLabelInfoForTABFile( TotalValueCoeff%labelinfo, OutputString)
	        call PrepareLabelInfoForTABFile( TotalQuantityCoeff%labelinfo, OutputString)
	        call WriteOneLineToTAB(' '//OutputString)
! quantifiers and LHS and "="
		if(.not.UseIndexStack) then
! ArgToAlls called earlier. Do not need it here
!DONE	          call ArgToAllsGP(CurrentSymbol%arg, OutputStringAlls)
!VALUE	          call CoeffVarRealToGP(TotalValueCoeff, TempString)
	          call CoeffVarRealToGP(TotalQuantityCoeff, TempString)
		else if(UseIndexStack) then
! ArgToAlls called earlier. Do not need it here
!DONE	          call ArgToAllsGPUseIndexStack(CurrentSymbol%arg, DimIndexStack, &
!DONE		    OutputStringAlls, TopIndexStack, IndexStackSets, IndexStackIndexes)
	          call CoeffVarRealToGPUseIndexStack( &
!VALUE				TotalValueCoeff, &
				TotalQuantityCoeff, &
			        DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, TempString)
		end if
! Write this 
		OutputString = trim(OutputStringAlls)//' '//trim(TempString)//' ='
	        call WriteOneLineToTAB('   '//OutputString)

! Mark this as endogenous
		call MarkAsEndogenous(TotalQuantityVar)

	      end if ! if(kpass.eq.3.or.kpass.eq.4) then

! NumTermsSoFar is used to decide if need "+" before this term
! If formula or side of equation ends with NumTermsSoFar still equal to 0,
!   need to add explicit "0" to that side of formula or equation. 
	      NumTermsSoFar=0

	      CurrentFunctionGP => FunctionGPList
	      do while(associated(CurrentFunctionGP))

		if (CurrentFunctionGP%IsDemandFunctionGP) then

		  UseThis = EqualStringsIgnoreCase( &
		          CurrentFunctionGP%functionMPSGE%demand%identtext, &
			  CurrentSymbol%name)

		  if(UseThis.and.kpass.eq.3) then
!
! [08/06/04] Look at the d: line. Need to add sum of final demands, each of which
!   is of the form revenue/price (in the levels). For example,
!   $demand:ra(h,i)
!     d:pc(i)
!  This adds SUM(h,RA(h,i)/PC(i)) to the total quantity demanded of PC(i)
! or, using the levels notation here, adds SUM(h,VI_RA(h,i)/PC_L(i)) to total quantity demanded of PC(i).
! Note that d: line domain must be a subset of the $demand: function domain.
! See the following example (part of FISCFED.MGE): 
!    $demand:state(r,eq)
!        e:pgrant(eq)    q:t0(r,eq)         r:trn(r,eq)
!        d:p(eq)
!  Here the d: line adds   SUM(r,VI_STATE(r,eq)/P_L(eq)) to total quantity of P(i) demanded
!    Here the Levels variable after $demand: is called TotalIncomeCoeff

		    ThisDLineArg => CurrentFunctionGP%functionMPSGE%demand%arg 
		    if(.not.IsSubdomainIgnoreOrder(ThisDLineArg, &
 					CurrentFunctionGP%functionMPSGE%firstrecord%firstfield%arg)) then
! (or) 					CurrentFunctionGP%TotalIncomeCoeff%arg)) then

!		      This is an error
		      call ErrorStop('d: field domain is not a subset of $demand: domain in $demand:'// &
			trim(CurrentFunctionGP%functionMPSGE%firstrecord%firstfield%data))
		    end if

! Sum over all sets in TotalIncomeCoeff which are not arguments of this commodity
! Use subroutine findsubdomain to work this out.
!       subroutine findsubdomain(d1,d2,subdomain) determines those elements of d1 which are not in d2.

		    call findsubdomain(CurrentFunctionGP%TotalIncomeCoeff%arg, &
			      ThisDLineArg,ThisSubdomain)
	            call WriteSumsGPUseIndexStack(ThisSubDomain, &
				DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
				SumString, NSum)
! If set price ranges over in d: line is different from the
!  set that argument of the price ranges over (as declared in $commodities section),
!   need to add a conditional sum.
		    CurrentLineDomain => ThisDLineArg
		    CurrentDeclaredDomain => CurrentSymbol%arg
		    CurrentArgNumber = 1
		    do while(associated(CurrentLineDomain))
			  if(.not.EqualStringsIgnoreCase(CurrentLineDomain%s%name, CurrentDeclaredDomain%s%name)) then
! [Even do this when set is an element]
!.NO	                    if(INDEX(CurrentLineDomain%s%name,'"').eq.0) then
	                      call WriteConditionalSumGP(CurrentLineDomain, &
				CurrentArgNumber, DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, ConditionalSumString)
! Add this to SumString and increase NSum
			      SumString = trim(SumString)//ConditionalSumString
			      NSum = NSum + 1
!.NO			    end if
			  end if ! if(.not.EqualStringsIgnoreCase(CurrentDomain%s%name, DeclaredDomain%s%name)) then
			  CurrentLineDomain => CurrentLineDomain%next
			  CurrentDeclaredDomain => CurrentDeclaredDomain%next
			  CurrentArgNumber = CurrentArgNumber + 1
		    end do ! while(associated(CurrentLineDomain))

! Term inside sum is TotalIncomeCoeff/ThisPriceCoeff
		    if(UseIndexStack) then
		      if(.not.WriteLinearMktClear) then
	                  call CoeffVarRealToGPUseIndexStack( &
				CurrentFunctionGP%TotalIncomeCoeff, &
			        DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, TempString)
	                  call CoeffVarRealToGPUseIndexStack( &
				ThisPriceCoeff, &
			        DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, TempString2)
		      end if
		    end if ! if(UseIndexStack) then
			
! End the sums
	            call EndSumsGP(NSum, EndSumString)
! Take these indexes off the index stack
		    TopIndexStack = TopIndexStack - NSum

! Must set OutputString in all cases. Initialise it in case.
		    if(NumTermsSoFar.gt.0) then
		          OutputString='+'
		    else
		          OutputString=''
		    end if

! SUM  of terms: TotalIncomeCoeff / ThisPriceCoeff
		    OutputString = trim(OutputString)//' '//trim(SumString)//' '// &
			        trim(TempString)//' / '//trim(TempString2)//' '//trim(EndSumString)
! Write this line
	    	    call WriteOneLineToTAB('     '//OutputString)

! Increment NumTermsSoFar
		    NumTermsSoFar = NumTermsSoFar + 1

		  end if ! if(UseThis.and.kpass.eq.3) then   ! (End of d: line case)

		  if(kpass.eq.4.or.kpass.eq.3) then
! Positive endowments count as supplies (KPASS=4)
! [08/06/04] Need to do this when KPASS=3 since negative endowments count as demands

! go through the e: fields if this is a $demand and KPASS=3,4
		    CurrentEndowmentGP => CurrentFunctionGP%FirstEndowmentGP
		    NumEndowmentGPDone = 0
		    do while(NumEndowmentGPDone.lt.CurrentFunctionGP.NumEFields)
		      UseThis = EqualStringsIgnoreCase( &
		          CurrentEndowmentGP%endowmentMPSGE%f%identtext, &
			  CurrentSymbol%name)

		      if(UseThis) then

! Sum over all sets in EndowQFieldValueCoeff which are not arguments of this commodity
! Use subroutine findsubdomain to work this out.
!       subroutine findsubdomain(d1,d2,subdomain) determines those elements of d1 which are not in d2.

		        call findsubdomain(CurrentEndowmentGP%EndowQFieldValueCoeff%arg, &
			      CurrentEndowmentGP%EndowPriceVar%arg,ThisSubdomain)
	                call WriteSumsGPUseIndexStack(ThisSubDomain, &
				DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
				SumString, NSum)
! If set price ranges over in e: line (or o: line or i: line) is different from the
!  set that argument of the price ranges over (as declared in $commodities section),
!   need to add a conditional sum.
			CurrentLineDomain => CurrentEndowmentGP%EndowPriceVar%arg
			CurrentDeclaredDomain => CurrentSymbol%arg
			CurrentArgNumber = 1
			do while(associated(CurrentLineDomain))
			  if(.not.EqualStringsIgnoreCase(CurrentLineDomain%s%name, CurrentDeclaredDomain%s%name)) then
! [Even do this when set is an element]
!.NO	                    if(INDEX(CurrentLineDomain%s%name,'"').eq.0) then
	                      call WriteConditionalSumGP(CurrentLineDomain, &
				CurrentArgNumber, DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, ConditionalSumString)
! Add this to SumString and increase NSum
			      SumString = trim(SumString)//ConditionalSumString
			      NSum = NSum + 1
!.NO			    end if
			  end if ! if(.not.EqualStringsIgnoreCase(CurrentDomain%s%name, DeclaredDomain%s%name)) then
			  CurrentLineDomain => CurrentLineDomain%next
			  CurrentDeclaredDomain => CurrentDeclaredDomain%next
			  CurrentArgNumber = CurrentArgNumber + 1
			end do ! while(associated(CurrentLineDomain))

!	  type (GPCoeffVarReal) :: EndowQFieldQuantityVar  !! %-change in quantity of each endowment  
!	  type (GPCoeffVarReal) :: EndowQFieldValueCoeff  !! value (level) of endowment

! SUM  of terms: EndowQFieldQuantityCoeff if are writing levels market clearing equation
! SUM  of terms: EndowQFieldValueCoeff * EndowQFieldQuantityVar if EndowQuantityVar is a %-change variable
! SUM  of terms: 100 * EndowPriceCoeff * EndowQFieldQuantityVar if EndowQuantityVar is a change variable

			ThisEndowValueCoeff = CurrentEndowmentGP%EndowQFieldValueCoeff
			ThisEndowQuantityVar = CurrentEndowmentGP%EndowQFieldQuantityVar
			ThisEndowPriceCoeff = CurrentEndowmentGP%EndowPriceCoeff 
			ThisEndowQuantityCoeff = CurrentEndowmentGP%EndowQFieldQuantityCoeff

			if(.not.UseIndexStack) then
			 if(kpass.eq.3.or.kpass.eq.4) then
! The formula case
!VALUE	                      call CoeffVarRealToGP(ThisEndowValueCoeff, TempString)
	                      call CoeffVarRealToGP(ThisEndowQuantityCoeff, TempString)
			 end if

			else if(UseIndexStack) then

			 if(kpass.eq.3.or.kpass.eq.4) then
! The formula & equation case
	                      call CoeffVarRealToGPUseIndexStack( &
!VALUE				ThisEndowValueCoeff, &
				ThisEndowQuantityCoeff, &
			        DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, TempString)
			 end if

			end if ! else if(UseIndexStack) then

! End the sums
	                call EndSumsGP(NSum, EndSumString)
! Take these indexes off the index stack
			TopIndexStack = TopIndexStack - NSum

! Must set OutputString in all cases. Initialise it in case.
		        OutputString = ''
		        if(NumTermsSoFar.gt.0) then
		          OutputString='+'
		        else
		          OutputString=''
		        end if

			if(kpass.eq.3.or.kpass.eq.4) then
! The formula & Equation case
! [08/06/04] Only add if the expression has the correct sign (positive when KPASS=4 or negative when KPASS=3)
			  if(kpass.eq.4) then
			    CompString = ' GT'
		            OutputString = trim(OutputString)//' '//trim(SumString)//' '// &
			      'IF['//trim(TempString)//trim(CompString)//' 0, '//trim(TempString)//'] '//trim(EndSumString)
			  else if(kpass.eq.3) then
			    CompString = ' LT'
		            OutputString = trim(OutputString)//' '//trim(SumString)//' '// &
! Add negative of the coefficient ThisEndowQuantityCoeff when are doing demands
			      'IF['//trim(TempString)//trim(CompString)//' 0, -'//trim(TempString)//'] '//trim(EndSumString)
			  end if
			end if
! Write this line
	    	        call WriteOneLineToTAB('     '//OutputString)

! Increment NumTermsSoFar
		        NumTermsSoFar = NumTermsSoFar + 1

		      end if  ! if(UseThis) then

		      NumEndowmentGPDone = NumEndowmentGPDone + 1
		      CurrentEndowmentGP => CurrentEndowmentGP%next
		    end do  ! while(NumEndowmentGPDone.lt.CurrentFunctionGP.NumEFields)

		  end if ! if(kpass.eq.4.or.kpass.eq.3) then  ! (end of e: line case)


!		 End "if (CurrentFunctionGP%IsDemandFunctionGP) then"
		else if (CurrentFunctionGP%IsProdFunctionGP) then

! go through the relevant netputGPs if this is a $prod function

		  CurrentNetputGP => CurrentFunctionGP%FirstNetputGP
		  NumNetputGPDone = 0
		  do while(NumNetputGPDOne.lt.(CurrentFunctionGP%NumIFields+CurrentFunctionGP%NumOFields))
		    PriceAtStartOfThisLine = EqualStringsIgnoreCase( &
		          			CurrentNetputGP%netputMPSGE%f%identtext, CurrentSymbol%name)
		    UseThis=((kpass.eq.4).and.CurrentNetputGP%netputMPSGE%output).or. &
		            ((kpass.eq.3).and.(.not.CurrentNetputGP%netputMPSGE%output))
		    UseThis = UseThis .and. PriceAtStartOfThisLine

		    if(UseThis) then

! Tricky example from SJMGE.MGE
! $commodities:
!  pc(SECT)              ! price of commodity
! $prod:xcom(SECT)          
!* Tricky. Can infer that SECT1 is a subset of SECT here since pc is defined over SECT
!*  but is also used over SECT1.
!  o:pc(SECT)         q:QCOM(SECT)
!  i:pc(SECT1)        q:QCOMIN(SECT1,SECT)
!  i:pf(FAC)          q:QFACIN(FAC,SECT)
! Here the ALLs in market clearing equation for pc must be over the set over which pc 
!  was declared in the $commodities section
! And must map indices accordingly. That is, need (is this correct??)
! (all,sect_1,SECT) QCOM(sect_1)*pc(sect_1) = SUM(sect1_1,SECT1, QCOMIN(sect1_1,sect_1)*pc(sect1_1)
! Considerable care will be needed to map the indices correctly. **


! Sum over all sets in IOQFieldValueCoeff which are not arguments of this commodity
! Use subroutine findsubdomain to work this out.
!       subroutine findsubdomain(d1,d2,subdomain) determines those elements of d1 which are not in d2.

		      call findsubdomain(CurrentNetputGP%IOQFieldValueCoeff%arg, &
			CurrentNetputGP%IOPriceVar%arg,ThisSubdomain)
	              call WriteSumsGPUseIndexStack(ThisSubDomain, &
			 DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
			 SumString, NSum)

! If set price ranges over in e: line (or o: line or i: line) is different from the
!  set that argument of the price ranges over (as declared in $commodities section),
!   need to add a conditional sum.
		      CurrentLineDomain => CurrentNetputGP%IOPriceVar%arg
		      CurrentDeclaredDomain => CurrentSymbol%arg
		      CurrentArgNumber = 1
		      do while(associated(CurrentLineDomain))
			  if(.not.EqualStringsIgnoreCase(CurrentLineDomain%s%name, CurrentDeclaredDomain%s%name)) then
! [Even do this when set is an element]
!.NO	                    if(INDEX(CurrentLineDomain%s%name,'"').eq.0) then
	                      call WriteConditionalSumGP(CurrentLineDomain, &
				CurrentArgNumber, DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, ConditionalSumString)
! Add this to SumString and increase NSum
			      SumString = trim(SumString)//ConditionalSumString
			      NSum = NSum + 1
!.NO			    end if
			  end if ! if(.not.EqualStringsIgnoreCase(CurrentDomain%s%name, DeclaredDomain%s%name)) then
			  CurrentLineDomain => CurrentLineDomain%next
			  CurrentDeclaredDomain => CurrentDeclaredDomain%next
			  CurrentArgNumber = CurrentArgNumber + 1
		      end do ! while(associated(CurrentLineDomain))

! SUM  of terms: IOQFieldQuantityCoeff if are writing levels market clearing equation
! SUM  of terms: IOQFieldValueCoeff * IOQFieldQuantityVar if IOQFieldQuantityVar is a %-change variable
! SUM  of terms: 100 * IOPriceCoeff * IOQFieldQuantityVar if IOQFieldQuantityVar is a change variable

		      if(.not.UseIndexStack) then
		       if(kpass.ge.3) then
! The formula case
!VALUE	                    call CoeffVarRealToGP(CurrentNetputGP%IOQFieldValueCoeff, TempString)
	                    call CoeffVarRealToGP(CurrentNetputGP%IOQFieldQuantityCoeff, TempString)
		       end if

		      else if(UseIndexStack) then
		       if(kpass.ge.3) then
! The formula case
	                    call CoeffVarRealToGPUseIndexStack( &
!VALUE			      CurrentNetputGP%IOQFieldValueCoeff, &
			      CurrentNetputGP%IOQFieldQuantityCoeff, &
			      DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, TempString)
		       end if

		      end if ! else if(UseIndexStack) then
! End the sums
	              call EndSumsGP(NSum, EndSumString)
! Take these indexes off the index stack
		      TopIndexStack = TopIndexStack - NSum

! WalrasEq case. If the omitted equation is "a+b=c+d", we are writing it as
!    "walrasslack = a+b-c-d"
! Must set OutputString in all cases. Initialise it in case.
		      OutputString = ''
		      if(NumTermsSoFar.gt.0) then
		        OutputString='+'
		      else
		        OutputString=''
		      end if

		      if(kpass.ge.3) then
! The formula case
		        OutputString = trim(OutputString)//' '//trim(SumString)//' '// &
			  trim(TempString)//' '//trim(EndSumString)
		      end if
! Write this line
!		      write(*,*)'Writing line: "'//trim(OutputString),'" to TAB file'
	    	      call WriteOneLineToTAB('     '//OutputString)

! Increment NumTermsSoFar
		      NumTermsSoFar = NumTermsSoFar + 1

!		     End "if(UseThis) then"
		    end if

! Increment NumNetputGPDOne
		    NumNetputGPDone = NumNetputGPDone + 1

		    CurrentNetputGP => CurrentNetputGP%next
		  end do ! while(associated(CurrentNetputGP))


!		 End "else if (CurrentFunctionGP%IsProdFunctionGP) then"
		end if

	        CurrentFunctionGP => CurrentFunctionGP%next
	      end do !  while(associated(CurrentFunctionGP))

	      if(kpass.eq.3.or.kpass.eq.4) then
! ";" to end formula & equation
		if(NumTermsSoFar.eq.0) then
		  call WriteOneLineToTAB('          0  ;')
		else
		  call WriteOneLineToTAB('             ;')
		end if
	      end if

!-------------------------------------------------------------------------------------------
! [03/06/04] When KPASS=3,4  write assertion that value of demand/supply exceeds zero for
!  all relevant indices (that is, those satisfying any condition in the declaration
!   of this commodity.
! This is what Tom calls sink/source
! Ideally this should test quantities not values. But at present have values readily
!  available so use them. Later it might be a good idea to define levels variables
!   representing total quantities (rather like those now there representing values)
!   and give equations for them. Then use those in these assertions.

	      if(kpass.eq.3.or.kpass.eq.4) then

! Start an Assertion(Initial)
		StatementStart = 'Assertion (Initial)'
! Write this out
	        call WriteOneLineToTAB(StatementStart)
! Labelling info for this formula
		if(kpass.eq.3) then
	          call PrepareLabelInfoForTABFile( 'Check nonzero demand for commodity '//trim(CurrentSymbol%name)//' (relevant indices)', &
			OutputString)
		else if(kpass.eq.4) then
	          call PrepareLabelInfoForTABFile( 'Check nonzero supply for commodity '//trim(CurrentSymbol%name)//' (relevant indices)', &
			OutputString)
		end if
	        call WriteOneLineToTAB(' '//OutputString)
! quantifiers and LHS and "="
! do not need to use index stack here
	        call ArgToAllsGP(CurrentSymbol%arg, SinkSourceOutputStringAlls)

! Is there a condition here? If so need to add it after the last "All".
	    	if(CurrentSymbol%lines%line%record%firstfield%condtn.ne.' ') then
              	  PriceExceptionStringGAMS  = trim(CurrentSymbol%lines%line%record%firstfield%condtn)
! Translate to GEMPACK, adding 'NE 0' at the end
! do not need to use index stack here
	      	  PriceExceptionString = ExpressionToGPSyntax2(PriceExceptionStringGAMS, .true., 'NE 0', &
	        	      .false., GPCoeffMPSGEHere)
! overwrite end ")" of last "All"
		  len1= LEN_TRIM(SinkSourceOutputStringAlls)
		  SinkSourceOutputStringAlls = SinkSourceOutputStringAlls(1:len1-1)//': '//trim(PriceExceptionString)//')' 
	    	end if

! Value is TotalValueCoeff
!VALUE	        call CoeffVarRealToGP(TotalValueCoeff, TempString)
! [08/06/04] Use TotalQuantityCoeff
	        call CoeffVarRealToGP(TotalQuantityCoeff, TempString)
! Write this 
		OutputString = trim(SinkSourceOutputStringAlls)//' '//trim(TempString)//' GT 0 ;'
	        call WriteOneLineToTAB('   '//OutputString)

! [09/06/04] Declare associated %-change variable and write equation connecting it to
!  the change version.

		call WriteEquationForPercentChangeVariable(TotalQuantityCoeff, TotalQuantityVar)

	      end if ! if(kpass.eq.3.or.kpass.eq.4) then
!-------------------------------------------------------------------------------------------

	      if(kpass.eq.4) then

! Add assertions about value of demand and supply
! {08/06/04] These are now about quantities
! Do slightly stricter assertion for intial data, less strict at other steps

! First a comment
	        call WriteOneLineToTAB(' ')
!VALUE	        OutputString = '! Checks that Total Value of Supply and Demand are equal for '//trim(CurrentSymbol%name)//' !'
	        OutputString = '! Checks that Total Quantity of Supply and Demand are equal for '//trim(CurrentSymbol%name)//' !'
	        call WriteOneLineToTAB(OutputString)

	        do assno=1,2

! Do Assertion (Inital) when ASSNO=1	
! Do Assertion (Always) when ASSNO=2

	          if(assno.eq.1) then
	            ISChar = 'I'
	          else if(assno.eq.2) then
	            ISChar = 'S'
	          end if	

! Assertion that total value of demand = total value of supply
	          if(assno.eq.1) then
	    	    StatementStart = 'Assertion (Initial)'
	            AssertString = 'Initial data'
	  	  else if(assno.eq.2) then
	    	    StatementStart = 'Assertion (Always)'
	            AssertString = 'At each step'
	  	  end if
! Write this out
	  	  call WriteOneLineToTAB(StatementStart)
! Assertion label
	          OutputString = ' # '//trim(AssertString)// &
! Shorten it a bit
! WAS		    '. Total Value of Demand = Total Value of Supply for '//&
!VALUE		    '. Total Value Demand = Total Value Supply for '//&
		    '. Total Quantity Demand = Total Quantity Supply for '//&
		    trim(CurrentSymbol%name)//' #'
! Write this out
	  	  call WriteOneLineToTAB(OutputString)
! Quantifiers
	  	  call ArgToAllsGP(CurrentSymbol%arg, OutputString)
! Write this out (if are any quantifiers)
		  if(OutputString.ne.' ') then
	  	    call WriteOneLineToTAB(OutputString)
		  end if
! LHS
!VALUE	          call CoeffVarRealToGP(TotalValueDemandCoeff, TempString)
	          call CoeffVarRealToGP(TotalQuantityDemandCoeff, TempString)
! RHS
!VALUE	          call CoeffVarRealToGP(TotalValueSupplyCoeff, TempString3)
	          call CoeffVarRealToGP(TotalQuantitySupplyCoeff, TempString3)

! Cannot expect exact equality. So instead write it as
!  Demand > 0.9999*Supply and Demand < 1.0001*Supply
! [Equality]	OutputString = trim(OutputString)//' '//trim(TempString)// &
! [Equality]	  ' = '//trim(TempString3)//' ;'
! Use BALTOLI or BALTOLS
!	  OutputString = trim(OutputString)//' '//trim(TempString)// &
!	    ' GT 0.9999*'//trim(TempString3)//' AND '//trim(TempString)// &
!	    ' LT 1.0001*'//trim(TempString3)//' ;'

! [26/04/04] Use GE and LE to cater for the case where the values being comared
!   are both zero.
!WAS	          TempString4 = '['//trim(TempString)// ' GT (1-BALTOL'//ISChar//')*'//trim(TempString3)//'] AND'
	          TempString4 = '['//trim(TempString)// ' GE (1-BALTOL'//ISChar//')*'//trim(TempString3)//'] AND'
!	          write(*,*)'TempString4 = ', trim(TempString4)
	          TempString2 = '   '//trim(TempString4)
	  	  call WriteOneLineToTAB(TempString2)
!WAS	  	  TempString5 = '['//trim(TempString)// ' LT (1+BALTOL'//ISChar//')*'//trim(TempString3)//'] ;'
	  	  TempString5 = '['//trim(TempString)// ' LE (1+BALTOL'//ISChar//')*'//trim(TempString3)//'] ;'
!	  	  write(*,*)'TempString5 = ', trim(TempString5)
	  	  TempString2 = '   '//trim(TempString5)
	  	  call WriteOneLineToTAB(TempString2)
		end do ! do assno=1,2

	      end if ! if(kpass.eq.4) then

!&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
	      if(kpass.eq.4) then

! [08/06/04] Write the market clearing equation for this commodity.
! The main part of the equation says Demand (TQD_) = Supply (TQS_)
! Put this inside IF test so that the main part of the equation is only
!   there if demand=supply>0.
! If is a condition on the declaration of this commodity, the main
!  part also goes inside an IF test that this condition is satisifed.  
! Add term saying price=1 if demand=supply=1 or if condition on declaration
!   of the commodity is not satisfied.

! The quantifiers at the start of this equation
! [08/06/04] Do not need to use index stack, now that have relatively simple form of this equation 
	        call ArgToAllsGP(CurrentSymbol%arg, OutputStringAlls)

	        call WriteStartMarketClearEquation( &
! [08/06/04] Do not need to use index stack, now that have relatively simple form of this equation 
!WAS	          InDField, ThisIsWalrasEq, WriteLinearMktClear, UseIndexStack, &
	          InDField, ThisIsWalrasEq, WriteLinearMktClear, .false., &
	          CurrentSymbol, WalrasSlackVar, WalrasSlackCoeff, &
	          DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
	          OutputStringAlls)

!   
! [05/05/04] Add a term to LHS of levels equation which sets ThisPriceVar to zero
!  if total value of demand in the relevant sector is zero (or? negative?)
! The rest of the equation only applies if total value of demand is different from that (eg positive).

! [08/06/04] Do not need to use index stack, now that have relatively simple form of this equation 
!NOSTACK		      if(.not.UseIndexStack) then
!VALUE	                call CoeffVarRealToGP(TotalValueDemandCoeff, TempString)
	                call CoeffVarRealToGP(TotalQuantityDemandCoeff, TempString)
	                call CoeffVarRealToGP(ThisPriceCoeff, TempString2)
!NOSTACK		      else if(UseIndexStack) then
!NOSTACK	                call CoeffVarRealToGPUseIndexStack( &
!VALUE				TotalValueDemandCoeff, &
!NOSTACK				TotalQuantityDemandCoeff, &
!NOSTACK			        DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, TempString)
!NOSTACK	                call CoeffVarRealToGPUseIndexStack( &
!NOSTACK				ThisPriceCoeff, &
!NOSTACK			        DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, TempString2)
!NOSTACK		      end if
		      ThisExceptionString = trim(TempString)//' GT 0'

! [10/05/04] See if is exception when this price was declared
	    	      if(CurrentSymbol%lines%line%record%firstfield%condtn.ne.' ') then
              		  PriceExceptionStringGAMS  = trim(CurrentSymbol%lines%line%record%firstfield%condtn)
! Translate to GEMPACK, adding 'NE 0' at the end
	      		  PriceExceptionString = ExpressionToGPSyntax3(PriceExceptionStringGAMS, .true., 'NE 0', .false., &
! [03/06/04] Add UseIndexStack and IndexStack stuff
! [08/06/04] Do not need to use index stack, now that have relatively simple form of this equation 
!WAS	  		      UseIndexStack, DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
	  		      .false., DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
	        	      GPCoeffMPSGEHere)
		      else
			  PriceExceptionString = ' '
	    	      end if

		      if(PriceExceptionString.ne.' ') then
			  ThisExceptionString = '{'//trim(ThisExceptionString)//'} AND {'// &
			    trim(PriceExceptionString)//'}'
		      end if

! The extra term on LHS of this equation
! [10/05/04] Include any exception when this price was declared
!WAS		        OutputString = 'IF[ '//trim(TempString)//' LE 0, '//trim(TempString2)//' - 1 ] +'
		      OutputString = 'IF[ NOT[ '//trim(ThisExceptionString)//'], '//trim(TempString2)//' - 1 ] +'
	              call WriteOneLineToTAB('   '//OutputString)
! The main part of the equation goes inside the next IF test.
!WAS		      OutputString = 'IF[ '//trim(Tempstring)//' GT 0,'
		      OutputString = 'IF[ '//trim(ThisExceptionString)//','
	              call WriteOneLineToTAB('   '//OutputString)
! [08/06/04] Put the main part of the equation on the LHS inside this IF.
	              call CoeffVarRealToGP(TotalQuantityDemandCoeff, TempString)
	              call CoeffVarRealToGP(TotalQuantitySupplyCoeff, TempString2)

! If ThisIsWalrasEq then these terms go on the RHS
		      OutputString = trim(TempString)//' - '//trim(TempString2)//' ]'
		      if(ThisIsWalrasEq) then
!  End the RHS
			OutputString = trim(OutputString)//' ;'
		      else
!  End the LHS and set RHS=0
			OutputString = trim(OutputString)//' = 0 ;'
		      end if
	              call WriteOneLineToTAB('     '//OutputString)

	              if(.not.ThisIsWalrasEq) then
!		  	  write(*,*)'Marking as endogenous:', trim(ThisPriceVar)
			  call MarkAsEndogenous(ThisPriceVar)
		      else if(ThisIsWalrasEq) then
!		  	  write(*,*)'Marking as endogenous:', trim(WalrasSlackVar%name)
	          	  call MarkAsEndogenous(WalrasSlackVar)
		      end if

	      end if ! if(kpass.eq.4) then
!&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&


!	     End "do kpass=KPassStart,KPassEnd"
	    end do


!	   End "if(CurrentSymbol%type.eq.'commodity') then"
	  end if

	  CurrentSymbol => CurrentSymbol%next
	end do 	! while(associated(CurrentSymbol))

	call WriteOneLineToTAB(' ')
	OutputString = '! End of market clearing equations !'
	call WriteOneLineToTAB(OutputString)

!  Re-initialize 'pre' messages again
	call InitializeMessages('pre',0)

	write(*,*)'Completed Market clearing equations'

	return
	end subroutine DoMarketClearingEquations

	subroutine WriteEquationForPercentChangeVariable(LevelsVariable, ChangeLinearVariable)
! [09/06/04] Write linear equation which says p_X = IF[X NE 0, (100/X)*c_X] if X is the
!   levels variable in question
! Also declare the %-change variable
! Note that the %-change variable introduced here is not added to GPNameList etc
!  [Accordingly do not need to mark it as endogenous.]

! Input
	type (GPCoeffVarReal) :: LevelsVariable
	type (GPCoeffVarReal) :: ChangeLinearVariable
! Local
	type (GPCoeffVarReal) :: PercentChangeLinearVariable
	character (len=512):: OutputStringAlls
	character(len=512) :: StatementStart, OutputString, TempString, TempString2, TempString3

	PercentChangeLinearVariable = ChangeLinearVariable
! Change name and VarType
	PercentChangeLinearVariable%VarType = 'p'
	if(ChangeLinearVariable%name(1:2).eq.'c_') then
	  PercentChangeLinearVariable%name='p_'//ChangeLinearVariable%name(3:)
	else
	  call InternalErrorStop('WriteEquationForPercentChangeVariable. Unexpected ChangeLinearVariable%name')
	end if

! Declare %-change variable
	StatementStart = 'Variable (Linear, Percent_Change)'
! Write this out
	call WriteOneLineToTAB(StatementStart)

! The quantifiers at the start of this equation
	call ArgToAllsGP(PercentChangeLinearVariable%arg, OutputStringAlls)
! The variables and coefficients
	call CoeffVarRealToGP(PercentChangeLinearVariable, TempString)
! Write this
	if(OutputStringAlls.ne.' ') then
	  OutputString = trim(OutputStringAlls)
	else
	  OutputString = ''
	end if
	OutputString = trim(OutputString)//' '//trim(TempString)
! Write this out
	call WriteOneLineToTAB('   '//OutputString)
! Write label
	call PrepareLabelInfoForTABFile( &
	          '%-change in '//trim(LevelsVariable%LabelInfo), OutputString)
	if(LEN_TRIM(OutputString).le.75) then
	  call WriteOneLineToTAB(' '//trim(OutputString)//' ;')
	else
	  call WriteOneLineToTAB(' '//trim(OutputString))
	  call WriteOneLineToTAB('        ;')
	end if

! The equation
	StatementStart = 'Equation (Linear)'
	OutputString = trim(StatementStart)//' E_'//trim(PercentChangeLinearVariable%name)
! Write this out
	call WriteOneLineToTAB(OutputString)
! Write label
	call PrepareLabelInfoForTABFile( &
	          '%-change in '//trim(LevelsVariable%LabelInfo), OutputString)
	call WriteOneLineToTAB(' '//OutputString)

! The quantifiers at the start of this equation
	call ArgToAllsGP(PercentChangeLinearVariable%arg, OutputStringAlls)
	if(OutputStringAlls.ne.' ') then
	      call WriteOneLineToTAB(' '//OutputStringAlls)
	end if

! The variables and coefficients
	call CoeffVarRealToGP(PercentChangeLinearVariable, TempString)
	call CoeffVarRealToGP(LevelsVariable, TempString2)
	call CoeffVarRealToGP(ChangeLinearVariable, TempString3)

! The equation
	OutputString = trim(TempString)//' ='
	call WriteOneLineToTAB('  '//OutputString)
	OutputString = 'IF[ '//trim(TempString2)//&
	  ' NE 0, {100/'//trim(TempString2)//'}*'//trim(TempString3)//'] ;'
	call WriteOneLineToTAB('    '//OutputString)

	return
	end subroutine WriteEquationForPercentChangeVariable

	subroutine StartTABGP

! Local
	type (symbol), pointer :: ThisSymbol
	character (len=llhd) HeadString
	character (len=80) TextLine, OutputString
	character (len=llst) :: BigSetName, SmallSetName, SetName, SetName2, SmallSetName2
	integer :: NumSubsetsHere, s1, s2, n1

10005	format(a)

! Coefficients used for checking balance
	call WriteOneLineToTAB(' ')
	OutputString = '! Coefficients used to check balance of data !'
	call WriteOneLineToTAB(OutputString)
	OutputString = 'Coefficient (Parameter) BALTOLI'
	call WriteOneLineToTAB(OutputString)
	OutputString = '  # Used to check initial database is balanced # ;'
	call WriteOneLineToTAB(OutputString)
	OutputString = 'Coefficient (Parameter) BALTOLS'
	call WriteOneLineToTAB(OutputString)
	OutputString = '  # Used to check database stays balanced at all steps # ;'
	call WriteOneLineToTAB(OutputString)
	OutputString = 'Formula (Initial) BALTOLI = 0.0001 ;' 
	call WriteOneLineToTAB(OutputString)
	OutputString = 'Formula (Initial) BALTOLS = 0.001 ;' 
	call WriteOneLineToTAB(OutputString)

! Do not declare file Input since (eg in twobytwo.mge) are no sets and no
!   data to read. Instead declare it just before the first read.
!  Use NumGPReads to tell when this is.

! Read all sets

	ThisSymbol => idlist
	do while(associated(ThisSymbol))
	  if (ThisSymbol%type.eq.'set') then
	    if(NumGPReads.eq.0) then
! Declare File Input
	      call WriteOneLineToTAB(' ')
	      call WriteOneLineToTAB('File Input # contains data and set elements # ;')
	      call WriteOneLineToTAB(' ')
	    end if
! Declare this set
	    call GetReadHeader(ThisSymbol%name, HeadString)
	    SetName = trim(ThisSymbol%name)
! In the idlist are sets corresponding to quoted elements (eg "lab") used. Do not
!  want to declare these or read their elements
	    if(INDEX(SetName,'"').eq.0) then
	      call upper(SetName)
	      TextLine='Set '//trim(SetName)//' Read Elements from File Input Header "'//HeadString//'" ;'
	    else
! Here make up a set to hold this single element
	      SetName2 = GetSingletonSetName(SetName)
	      n1=LEN_TRIM(SetName)
	      TextLine='Set '//trim(SetName2)//' ('//SetName(2:n1-1)//') ;'
	    end if
	    call WriteOneLineToTAB(TextLine)
	    NumGPReads = NumGPReads + 1
	  end if
	  ThisSymbol => ThisSymbol%next
	end do

! Write the subset statements (if any)
! First see if are any - if so, write heading

	NumSubsetsHere = 0
	do s1=1,NumSets
	  do s2=1,NumSets
	    if(IsSubsetGP(s1,s2)) then
	        NumSubsetsHere = NumSubsetsHere + 1
	    end if
	  end do
	end do

	if(NumSubsetsHere.gt.0) then
	  call WriteOneLineToTAB(' ')
	  TextLine = '! Subset declarations (inferred from MGE file) ! '
	  call WriteOneLineToTAB(TextLine)
	end if

	do s1=1,NumSets
	  do s2=1,NumSets
	    if(IsSubsetGP(s1,s2)) then
! set number s1 is a subset of set number s2
! Don't do this when small set is an element
	      SmallSetName = GetSetName(s1)
	      if(INDEX(GetSetName(s1),'"').eq.0) then
	        SmallSetName2 = GetSetName(s1)
	      else
	        SmallSetName2 = GetSingletonSetName(SmallSetName)
	      end if
	      BigSetName = GetSetName(s2)
	      call upper(BigSetName)
	      call upper(SmallSetName2)
	      TextLine='Subset '//trim(SmallSetName2)//' is subset of '//trim(BigSetName)//' ;'
	      call WriteOneLineToTAB(TextLine)
	    end if
	  end do
	end do

	return
	end subroutine StartTABGP

	subroutine WriteSumsGP(ThisDomain, OutputString, NSum)
! Input
	type (domain), pointer :: ThisDomain
! Output
	character (len=*), intent(out) :: OutputString
	integer, intent(out) :: NSum
! Local
	type (domain), pointer :: CurrentDomain
	character (len=128) :: CurrentIndex, TempString 

! The RHS  "SUM{<index>,<set>,<InputQuantity>} ;"
	NSum = 0
	CurrentDomain => ThisDomain
	OutputString = ''
	do while(associated(CurrentDomain))
! Sum over this set
	  call GPSet2Index(CurrentDomain%s, CurrentIndex)
	  TempString = 'SUM{'//trim(CurrentIndex)//','//trim(CurrentDomain%s%name)//','
	  OutputString = trim(OutputString)//trim(TempString)
	  NSum = NSum + 1
	  CurrentDomain => CurrentDomain%next
	end do

	return
	end subroutine WriteSumsGP

	subroutine WriteSumsGPUseIndexStack(ThisDomain, &
	  DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
	  OutputString, NSum)
! Input
	type (domain), pointer :: ThisDomain
	integer, intent(in) :: DimIndexStack
! Input/Output
	integer, intent(in out) :: TopIndexStack
	character (len=*), intent(in out) :: IndexStackSets(DimIndexStack)
	character (len=*), intent(in out) :: IndexStackIndexes(DimIndexStack)
! Output
	character (len=*), intent(out) :: OutputString
	integer, intent(out) :: NSum
! Local
	type (domain), pointer :: CurrentDomain
	character (len=128) :: CurrentIndex, TempString 

! The RHS  "SUM{<index>,<set>,<InputQuantity>} ;"
	NSum = 0
	CurrentDomain => ThisDomain
	OutputString = ''
	do while(associated(CurrentDomain))
! Sum over this set
	  call GPSet2Index(CurrentDomain%s, CurrentIndex)
	  TempString = 'SUM{'//trim(CurrentIndex)//','//trim(CurrentDomain%s%name)//','
	  OutputString = trim(OutputString)//trim(TempString)
	  NSum = NSum + 1

! Add this to the index stack
	  TopIndexStack = TopIndexStack + 1
	  if(TopIndexStack.gt.DimIndexStack) then
	    call InternalErrorStop('WriteSumsGPUseIndexStack. Index Stack is not large enough.')
	  end if
	  IndexStackSets(TopIndexStack) = CurrentDomain%s%name
	  IndexStackIndexes(TopIndexStack) = CurrentIndex

	  CurrentDomain => CurrentDomain%next
	end do

	return
	end subroutine WriteSumsGPUseIndexStack

	subroutine WriteConditionalSumGP( &
! Input
	  ThisDomain, CurrentArgNumber, &
	  DimTheseArgs, &
! Input/Output
	  TopIndexStack, & 
	  IndexStackSets, IndexStackIndexes, &
! Output
	  OutputString)
! Input
	type (domain), pointer :: ThisDomain
	integer, intent(in) :: DimTheseArgs, CurrentArgNumber
! Input/Output
	integer, intent(in out) :: TopIndexStack
	character (len=*), intent(in out) :: IndexStackSets(DimTheseArgs)
	character (len=*), intent(in out) :: IndexStackIndexes(DimTheseArgs)
! Output
	character (len=*), intent(out) :: OutputString
! Local
	type (domain), pointer :: CurrentDomain
	type (symbol), pointer :: CurrentSet
	character (len=128) :: CurrentIndex, TempString
	character (len=llst) :: SumSetName
	integer :: ThisArgNumber 

! "SUM{<index>,<set> : <condition>,"
	OutputString = ''
! Run through ThisDomain to find the set symbol for CurrentArgNumber
	CurrentDomain => ThisDomain
	ThisArgNumber = 0
	do while(ThisArgNumber.lt.CurrentArgNumber)
	  ThisArgNumber = ThisArgNumber + 1
	  if(ThisArgNumber.eq.CurrentArgNumber) then
! Sum over CurrentSet - taken from ThisDomain
	    CurrentSet => CurrentDomain%s	    
	  end if
	  CurrentDomain => CurrentDomain%next
	end do ! while(ThisArgNumber.lt.CurrentArgNumber)
! If set is a quoted element, convert to the corresponding GEMPACK set
	if(INDEX(CurrentSet%name,'"').gt.0) then
	  SumSetName = GetSingletonSetName(CurrentSet%name)
	else
	  SumSetName = CurrentSet%name
	end if
! Sum over this set
	call GPSetName2Index(SumSetName, CurrentIndex)
	TempString = 'SUM{'//trim(CurrentIndex)//','//trim(SumSetName)
	OutputString = trim(OutputString)//trim(TempString)
! Add the condition ": CurrentIndex = <index-from-stack>,"
	TempString = ': '//trim(CurrentIndex)//' = '//trim(IndexStackIndexes(CurrentArgNumber))
	OutputString = trim(OutputString)//trim(TempString)//','
!	write(*,*)'WriteConditionalSumGP. OutputString is: ', trim(OutputString)

! Add this index to the Index Stack
	TopIndexStack = TopIndexStack + 1
	if(TopIndexStack.gt.DimTheseArgs) then
	  call InternalErrorStop('WriteConditionalSumGP. Index Stack is not large enough.')
	end if
	IndexStackSets(TopIndexStack) = SumSetName
	IndexStackIndexes(TopIndexStack) = CurrentIndex
!	write(*,*) 'WriteConditionalSumGP. TopIndexStack is ', TopIndexStack

	return
	end subroutine WriteConditionalSumGP


	subroutine EndSumsGP(NSum, OutputString)
! Input
	integer, intent(in) :: NSum
! Output
	character (len=*), intent(out) :: OutputString
! Local
	integer :: i
 
	OutputString=''
	do i = 1, NSum
	  OutputString = trim(OutputString)//'}'
	end do

	return
	end subroutine EndSumsGP

	subroutine OutputMPSFunctionAsGPComment(ThisFunction)
! Input
	type (function), pointer :: ThisFunction
! Local
	type (GPCoeffVarReal) :: ThisTopVar
	type (GPCoeffVarReal) :: ThisElasticity
	character (len=128) :: TempString
	type (record), pointer :: CurrentRecord
	type (line), pointer :: CurrentLine, ThisLine
!	integer NRecords, KRecord
	logical :: FoundNextFunction
	integer :: NumLineWritten
	logical :: UseOutputMGEFunction

10015	format(a)

	TempString = trim(ThisFunction%firstrecord%firstfield%data)
! Blank line
 	write(iotabgp,10015) ' '
 	write(iotabgp,10015) '! '//trim(ThisFunction%firstrecord%firstfield%label)// &
	  ':'//trim(ThisFunction%firstrecord%firstfield%data)//' !'
!	NRecords = ThisFunction%nrecord
!	write(*,*)'NRecords = ', NRecords
!	KRecord = 0
! Write out the records as a strong comment
 	write(iotabgp,10015) '![[!'

! [18/04/04] Replace the code echoing the lines by a call to routine OutputMGEFunction.
! Routine OutputMGEFunction does the job more simply and does not produce blank lines
!  after the function.
! However, at present it does not show comment lines (beginning with "*" inside function blocks.
! This is because Tom's routine readline skips comment lines.
! This is unfortunate since it means do not see the original MGE nests as comments in the TAB file.
! So for the present, revert to Ken's old code.
!  Perhaps can use OutputMGEFunction routine if it is safe to not ignore comment lines in Tom's readline routine.
! For the present set UseOutputMGEFunction false.
!
	UseOutputMGEFunction = .false.

	if(UseOutputMGEFunction) then 

!(call)	  call OutputMGEFunction(ThisFunction, OutputAsMGEComment, OutputUnit, TruncateLines, TruncateMaxLength)
	  call OutputMGEFunction(ThisFunction, .false., iotabgp, .true., 80)

	else if(.not.UseOutputMGEFunction) then 

	    NumLineWritten = 0

! ThisLine may consist of several actual lines from the file
	    ThisLine => ThisFunction%firstrecord%line
	    FoundNextFunction = .false.
	    do while(associated(ThisLine).and. (.not.FoundNextFunction))

! Don't know where this function ends. So test every line to see if it starts
!  with $. If so, set FoundNextFunction true, which will stop the writing.
! But don't test the first line, which is the start of the current function
	      if(NumLineWritten.gt.0.and.ThisLine%text.ne.' ') then
		TempString = ThisLine%text
! Remove blanks at the start until find first non-blank character
		do while(TempString(1:1).eq.' ')
		  TempString = TempString(2:)						      
		end do ! while(TempString(1:1).eq.' ')
		if(TempString(1:1).eq.'$') then
		  FoundNextFunction = .true.
		end if
	      end if ! if(NumLineWritten.gt.0.and.ThisLine%text.ne.' ') then
	      if(.not.FoundNextFunction) then
! Lines may be too long. Use routine OutputOneMPSLineToGP to break them up
! (was)	      write(iotabgp,10015) trim(CurrentLine%text)
! [18/04/04] Don't output blank lines
		if(ThisLine%text.ne.' ') then
! [18/04/04] Use routine OutputTruncateOneMGELine
!WAS	          call OutputOneMPSLineToGP(ThisLine%text)
!call	          call OutputTruncateOneMGELine(ThisLine, OutputUnit, MaxLength)
	          call OutputTruncateOneMGELine(ThisLine%text, iotabgp, 80)
		end if
		NumLineWritten = NumLineWritten + 1
	      end if ! if(.not.FoundNextFunction) then
	      ThisLine => ThisLine%next
	    end do ! while(associated(ThisLine))
	end if ! if(UseOutputMGEFunction) then..else.. 

 	write(iotabgp,10015) '!]]!'

	return
	end subroutine OutputMPSFunctionAsGPComment

	logical function IsReal(ThisString)
! Input
	character (len=*) ThisString
! Local
	integer LengthString, i
	character (len=12) RealChar
	character ThisChar
	intrinsic Index

	RealChar='0123456789.-'

	LengthString = LEN(trim(ThisString))
	IsReal = .true .
	do i = 1, LengthString
	  ThisChar = ThisString(i:i)
	  if(Index(RealChar,ThisChar).eq.0) then
	    IsReal = .false.
	  end if
	end do

	return
	end function IsReal

	subroutine GetProdPriceQuantity(ThisFunction, IOType, ThisPrice, ThisQuantity)
! Input
	type (function), pointer :: ThisFunction
	character, intent(in) :: IOType   ! 'i' or 'o'
! Output
	type (GPCoeffVarReal) :: ThisPrice, ThisQuantity
! Local
	type (record), pointer :: r
	type (field), pointer :: fnf
	type (nest), pointer :: outputs, inputs
	type (netputlist), pointer :: elements
	type (netput), pointer :: ThisNetPut
	type (field), pointer :: IOField, qref, pref
	logical :: UseThis, UseThis1, UseThis2

!	write(*,*)' GetProdPriceQuantity: IOType=', IOType
	r => ThisFunction%firstrecord
	fnf => r%firstfield
	if(IOType.eq.'o') then
	  outputs => ThisFunction%outputs
	  elements => outputs%elements
	else if(IOType.eq.'i') then
	  inputs => ThisFunction%inputs
	  elements => inputs%elements
!	else
!	  error
	end if
	do while (associated(elements)) 
	  ThisNetPut => elements%np
	  IOField => ThisNetPut%f   ! I: or O: field
	  qref => ThisNetPut%qref
	  pref => ThisNetPut%pref
	  UseThis1 = (IOType.eq.'o' .and. ThisNetPut%output)  
	  UseThis2 = (IOType.eq.'i' .and. .not.ThisNetPut%output)
	  UseThis = UseThis1.or.UseThis2  
	  if (UseThis) then
	    ThisPrice%type = 'v' ! Variable
	    ThisPrice%name = IOField%ident%name
	    ThisPrice%arg => IOField%arg	    
	    ThisQuantity%type = 'c' ! Coefficient
	    ThisQuantity%name = qref%ident%name
	    ThisQuantity%arg => qref%arg	    
!  Are done - return
	    return
	  end if
	  elements => elements%next
	end do

	return
	end subroutine GetProdPriceQuantity

	subroutine GetInputsSubDomain(ThisFunction, ThisSubdomain)
! Input
	type (function), pointer :: ThisFunction
! Output
	type (domain), pointer :: ThisSubdomain
! Local
	type (record), pointer :: r
	type (field), pointer :: fnf
	type (nest), pointer :: outputs, inputs
	type (netputlist), pointer :: elements
	type (netput), pointer :: ThisNetput
	logical :: DoneOk

	DoneOk = .false .
	r => ThisFunction%firstrecord
	fnf => r%firstfield
	inputs => ThisFunction%inputs
	elements => inputs%elements
	if (associated(elements)) then 
	  ThisNetput => elements%np
	  if(associated(ThisNetput)) then
	    ThisSubdomain => ThisNetput%sd
	    DoneOk = .true .
	  end if
	end if

	if(.not.DoneOk) then
	  write(*,*)'GetInputsSubDomain - not done ok'
	end if

	return
	end subroutine GetInputsSubDomain

	subroutine ReadCoeffGP(ThisCoefficient)
! Input
	type (GPCoeffVarReal) :: ThisCoefficient
! Local
	character (len=llhd) :: HeadString
	character (len=80) :: TextLine, CoeffName 	

10005	format(a)

	call GetReadHeader(ThisCoefficient%name, HeadString)
	CoeffName=trim(ThisCoefficient%name)
	call upper(CoeffName)
	TextLine = 'Read '//trim(CoeffName)//' from File Input Header "'//HeadString//'" ;'
	write(iotabgp, 10005) trim(TextLine)

	return
	end subroutine ReadCoeffGP	

	subroutine InitializeGPCoeffVarReal(ThisType, ThisGPCoeffVarReal)
! Input
	character (len=*), intent(in) :: ThisType  ! 'v', 'c' or 'r'
! Output
	type (GPCoeffVarReal), intent(out) :: ThisGPCoeffVarReal
!
!  character :: type  ! 'c' for coefficient or 'v' for variable or 'r' for real
!  character (len=15) :: name    ! Coeff/Var name or Real as string
!  type (domain), pointer :: arg      ! Sets over which arguments range
!  character (len=80) :: labelinfo  ! labelling information (between #)
! Next two only apply to a variable
!  character :: vartype  ! 'p' for %-change, 'c' for change
!  type (GPCoeffVarReal) :: OrigLevel  ! Coeff or Real which is the ORIG_LEVEL ! ignore if OrigLevel%name is ' '
! Next only applies to a coefficient
!  logical :: IsParam  ! Tells if this coefficient is a parameter
! Next applies only to coefficients and levels variables
!  logical :: IsGE0 ! Tells if this must be non-negative
!
	ThisGPCoeffVarReal%type = ThisType
	ThisGPCoeffVarReal%name = ' '
	nullify(ThisGPCoeffVarReal%arg)
	ThisGPCoeffVarReal%labelinfo = ' '
	if(ThisType.eq.'v') then
	  ThisGPCoeffVarReal%VarType = 'p'
	else
	  ThisGPCoeffVarReal%VarType = ' '
	end if
	ThisGPCoeffVarReal%OrigLevel = ' '
	ThisGPCoeffVarReal%IsParam = .false.
	ThisGPCoeffVarReal%IsGE0 = .true.

	return
	end subroutine InitializeGPCoeffVarReal

	subroutine MarkAsEndogenous(ThisGPVar)
! Input/Output
	type (GPCoeffVarReal) :: ThisGPVar
! Local
	type (GPName), pointer :: CurrentGPName
	logical :: found

! ?? Later may need to take into account sets??

! Run through GPNameList to find this name, and mark
	found = .false.
	CurrentGPName => GPNameList
	do while(associated(CurrentGPName).and.(.not.found))
	  if(EqualStringsIgnoreCase(ThisGPVar%name,CurrentGPName%name)) then
	    found = .true.
	    CurrentGPName%ExogEndogStatus = 'n'
	  end if
	  CurrentGPName => CurrentGPName%next
	end do ! while(associated(CurrentGPName).and.(.not.found))

	if(.not.found) then
	  call InternalErrorStop('MarkAsEndogenous. Did not find '//trim(CurrentGPName%name)//' in GPNameList')		
	end if ! if(.not.found) then

	return
	end subroutine MarkAsEndogenous

	subroutine WriteArguments(FirstArg, OutputText, LenOutput)
! Input
	type (domain), pointer :: FirstArg
! Output
	character (len=255) OutputText
	integer LenOutput
! Local
	type (domain), pointer :: CurrentArg
	type (symbol), pointer :: CurrentSet

10017   format(2x,3a)
	OutputText = ''
	LenOutput = 0	
	CurrentArg => FirstArg	
	do while(associated(CurrentArg))
	  CurrentSet => CurrentArg%s
	  if(.not.associated(CurrentSet)) then
	    call InternalErrorStop('WriteArguments. CurrentSet is not associated.')
	  end if
	  OutputText(LenOutput+1:) = trim(CurrentSet%name)//' '
	  LenOutput = LenOutput + LEN(trim(CurrentSet%name))+1
!	  write(*,*)'WriteArguments. OutputText is:', trim(OutputText(1:LenOutput))
	  CurrentArg => CurrentArg%next
	end do
!	write(*,10017) 'Arguments: ', OutputText(1:LenOutput) 

	return
	end subroutine WriteArguments 
	
	subroutine WriteRecord(DescText, ThisRecord)
! Input
	character(len=*), intent(in) :: DescText
	type (record), pointer :: ThisRecord
! Local
	type (record), pointer :: CurrentRecord
	type (field), pointer :: CurrentField

	CurrentRecord => ThisRecord
	do while(associated(CurrentRecord))
!	  write(*,*)DescText, ' WriteRecord - a new record '
	  CurrentField => CurrentRecord%firstfield
	  do while(associated(CurrentField))
	    call WriteField('Next field in record', CurrentField)
	    CurrentField => CurrentField%next 
	  end do
	  CurrentRecord => CurrentRecord%next
	end do	

	return
	end subroutine WriteRecord
	
	subroutine WriteField(DescText, ThisField)
! Input
	character(len=*), intent(in) :: DescText
	type (field), pointer :: ThisField
! Local
	character*256 OutputText
	integer LenOutput

10017   format(2x,3a)

	if (associated(ThisField)) then
	  write(*,10017) DescText, '%data: ', trim(ThisField%data)
	  if(associated(ThisField%ident)) then
	    write(*,10017) DescText, '%ident%name: ', trim(ThisField%ident%name)
	  end if
	  call WriteArguments(ThisField%arg, OutputText, LenOutput) 
	  write(*,10017) DescText, ' Arguments: ', OutputText(1:LenOutput)
	end if

	return
	end subroutine WriteField

	subroutine GPSetName2Index(CurrentSetName, CurrentIndex)
! [01/01/04] Extracted from routine GPSet2Index
! Input
	character (len=*), intent(in) :: CurrentSetName
! Output
	character (len=*), intent(out) :: CurrentIndex
! Local
	character (len=llindex) :: IndexRoot, IndexRoot1, AddString, TryIndex
	type(symbol), pointer :: CurrentSymbol
	logical :: IsASetName, Finished
	integer :: i
!

! Truncate IndexRoot to at most LLINDEX-3 characters
	IndexRoot1 = CurrentSetName
	IndexRoot = IndexRoot1(1:llindex-3)

! Add integers to the end until find something which is not the name of a set.
	i = 1
	Finished = .false.
	do while(i.le.99 .and. .not.Finished)
	  AddString = PosintToString(i)
	  TryIndex = trim(IndexRoot)//'_'//AddString
!??	  TryIndex = trim(IndexRoot)//AddString
! Is this the name of a set? Go through the list of symbols in idlist to check.

! Really should also check whether this is the name of a currently active index. **
! To do that would need to keep a list of those and keep the list up-to-date.

	  IsASetName = .false.
	  CurrentSymbol => idlist
	  do while(associated(CurrentSymbol).and. (.not.IsASetName))
	    if(CurrentSymbol%type.eq.'set') then
	      if(EqualStringsIgnoreCase(TryIndex,CurrentSymbol%name)) then
	        IsASetName = .true.
	      end if
	    end if
	    CurrentSymbol => CurrentSymbol%next
	  end do ! while(associated(CurrentSymbol))

	  if(.not.IsASetName) then
	    CurrentIndex = TryIndex
	    Finished=.true.
	  end if
	
! Increment I
	  i = i+1
	end do ! while(i.le.99 .and. .not.Finished)

	return
	end subroutine GPSetName2Index

	subroutine GPSet2Index(CurrentSet, CurrentIndex)
! Input
	type (symbol), pointer :: CurrentSet
! Output
	character (len=*), intent(out) :: CurrentIndex
! Local
	character (len=llindex) :: IndexRoot, IndexRoot1, AddString, TryIndex
	type(symbol), pointer :: CurrentSymbol
	logical :: IsASetName, Finished
	integer :: i
!

! The CurrentSet passed here may be a quoted element. If so, set CurrentIndex
!  to equal CurrentSet
	if(CurrentSet%name(1:1).eq.'"') then
	  CurrentIndex = CurrentSet%name
	  return
	end if

! Need to check that the index we output is not the name of a set. [If it
!   is, TABLO will object.]
! Also need to check that the name is not too long.

! [01/01/04] Call routine GPSetName2Index
	call GPSetName2Index(CurrentSet%name, CurrentIndex)

	return
	end subroutine GPSet2Index

! Next replaced by a test running through GPDeclarationList
! [15/03/04] Call this HasBeenDeclaredGPOld to distinguish from the newer one
!	logical function HasBeenDeclaredGPOld(ThisSymbol)
! Tells if ThisSymbol has already been declared
! Input
!	type (symbol), pointer :: ThisSymbol
! Local
!	type (symbol), pointer :: TestSymbol
!	character(len=31) ThisName, TestName

!	HasBeenDeclaredGPOld = .false.

!	if(.not.associated(ThisSymbol)) then
!	  write(*,*) 'HasBeenDeclaredGPOld - symbol is not associated'
!	  return
!	end if
!	ThisName = trim(ThisSymbol%name)
!	call lower(ThisName)

! Run through all the symbols (they are in idlist) 
!  to find this one and check if it is declared
!	TestSymbol => idlist ;
!	do while(associated(TestSymbol))
!	  TestName = trim(TestSymbol%name)
!	  call lower(TestName)
! Are the two names the same ?
!	  if (TestName.eq.ThisName) then
!	    if(TestSymbol%DeclaredGP) then
!	      HasBeenDeclaredGPOld = .true.
!	      write(*,*)'HasBeenDeclaredGPOld:',trim(ThisName),' has been declared'
!	      Exit
!	    else
!	      write(*,*)'HasBeenDeclaredGPOld:',trim(ThisName),' says not declared'
!	    end if
!	  end if
!	  TestSymbol => TestSymbol%next
!	end do 

!	return
!	end function HasBeenDeclaredGPOld

! [15/03/04] No longer need this routine
!	subroutine MarkAsDeclaredGP(ThisSymbol)
! Indicate that ThisSymbol has been declared
! Input and output
!	type (symbol), pointer :: ThisSymbol
! Local
!	type (symbol), pointer :: TestSymbol
!	character(len=31) ThisName, TestName

!	ThisName = trim(ThisSymbol%name)
!	call lower(ThisName)

! Run through all the symbols (they are in idlist) 
!  to find this one and then mark it as declared
!	TestSymbol => idlist ;
!	do while(associated(TestSymbol))
!	  TestName = trim(TestSymbol%name)
!	  call lower(TestName)
! Are the two names the same ?
!	  if (TestName.eq.ThisName) then
!	    TestSymbol%DeclaredGp = .true .
!	    write(*,*)'MarkAsDeclaredGP:',trim(ThisName),' now declared'
!	  end if
!	  TestSymbol => TestSymbol%next
!	end do 

! Temporary
! Run through all the symbols again 
!  to find this one and then check it is shown as declared
!	TestSymbol => idlist ;
!	do while(associated(TestSymbol))
!	  TestName = trim(TestSymbol%name)
!	  call lower(TestName)
! Are the two names the same ?
!	  if (TestName.eq.ThisName) then
!	    if(TestSymbol%DeclaredGp) then
!	      write(*,*)'MarkAsDeclaredGP:',trim(ThisName),' shown as declared'
!	    else
!	      write(*,*)'MarkAsDeclaredGP:',trim(ThisName),' NOT shown as declared'
!	    end if
!	  end if
!	  TestSymbol => TestSymbol%next
!	end do 

!	return
!	end subroutine MarkAsDeclaredGP

	subroutine ArgToAllsGP(TheseArgs, OutputString)
! Input
	type (domain), pointer :: TheseArgs
! Output
	character (len=*), intent(out) :: OutputString
! Local
	integer LenOutputString
	type (domain), pointer :: CurrentArgument
	type (symbol), pointer :: CurrentSet
	character (len=128) CurrentIndex, CurrentAll
	integer LengthCurrentAll

	OutputString = ''
	LenOutputString = 0 

	CurrentArgument => TheseArgs
! The ALLs
	do while(associated(CurrentArgument))
	  CurrentSet => CurrentArgument%s
	  call GPSet2Index(CurrentSet, CurrentIndex)
	  CurrentAll = '(All,'//trim(CurrentIndex)//','//trim(CurrentSet%name)//')'
	  LengthCurrentAll = 7 + LEN(trim(CurrentIndex)) + LEN(trim(CurrentSet%name)) 
	  OutputString = OutputString(1:LenOutputString) // CurrentAll
	  LenOutputString = LenOutputString + LEN(trim(CurrentAll))
	  CurrentArgument => CurrentArgument%next
	end do

	return
	end subroutine ArgToAllsGP

	subroutine ArgToAllsGPUseIndexStack(TheseArgs, DimTheseArgs, &
		OutputString, TopIndexStack, IndexStackSets, IndexStackIndexes)
! This is used to get the quantifiers for the market clearing equation.
! The indexes used are different from those given by Set2Index.
!  The sets indexes range over and the indexes used are returned in 
!    arrays IndexStackSets (the sets) and IndexStackIndexes (the indexes). [These arrays
!   are like the relevant things in the index stack in the code for the program TABLO.]
! Input
	type (domain), pointer :: TheseArgs
	integer, intent(in) :: DimTheseArgs
! Output
	character (len=*), intent(out) :: OutputString
	integer, intent(out) :: TopIndexStack
	character (len=*), intent(out) :: IndexStackSets(DimTheseArgs)
	character(len=*), intent(out) :: IndexStackIndexes(DimTheseArgs)
! Local
	integer LenOutputString
	type (domain), pointer :: CurrentArgument
	type (symbol), pointer :: CurrentSet
	character (len=128) CurrentIndex, CurrentAll
	integer LengthCurrentAll, NumAllsDone

	OutputString = ''
	LenOutputString = 0
	NumAllsDone = 0 

	CurrentArgument => TheseArgs
! The ALLs
	do while(associated(CurrentArgument))
	  NumAllsDone = NumAllsDone + 1
	  CurrentSet => CurrentArgument%s
	  call GPSet2Index(CurrentSet, CurrentIndex)
! For the present, just "mess" this about a bit. Later will probably need
!  to get more sophisticated
	  CurrentIndex=trim(CurrentIndex)//'@'
	  CurrentAll = '(All,'//trim(CurrentIndex)//','//trim(CurrentSet%name)//')'
	  LengthCurrentAll = 7 + LEN(trim(CurrentIndex)) + LEN(trim(CurrentSet%name)) 
	  OutputString = OutputString(1:LenOutputString) // CurrentAll
	  LenOutputString = LenOutputString + LEN(trim(CurrentAll))
! Add to output arrays
	  IndexStackSets(NumAllsDone) = CurrentSet%name
	  IndexStackIndexes(NumAllsDone) = CurrentIndex
	  CurrentArgument => CurrentArgument%next
	end do

	TopIndexStack = NumAllsDone

	return
	end subroutine ArgToAllsGPUseIndexStack

	subroutine CoeffVarRealToGP(ThisCoeffVarReal, OutputString)
! Writes coeff/var followed by its arguments
! [24/03/04] Add the possibility of a real here
! Input
	type (GPCoeffVarReal) :: ThisCoeffVarReal
! Output
	character (len=*), intent(out) :: OutputString
! Local
	type (domain), pointer :: TheseArgs
	character (len=512) :: ArgString

	if(ThisCoeffVarReal%type.eq.'r') then
	  OutputString = ThisCoeffVarReal%name
	else
! Coeff or Variable
	  OutputString = ThisCoeffVarReal%name
	  if(ThisCoeffVarReal%type.eq.'c') then
! Upper case for Coefficients
	    call upper(OutputString)
	  end if
	  TheseArgs => ThisCoeffVarReal%arg
	  call ArgToGP(TheseArgs, ArgString)
	  if(ArgString.ne.'') then
	    OutputString = trim(OutputString)//'('//trim(ArgString)//')'
	  end if
	end if
	OutputString = trim (OutputString)

	return
	end subroutine CoeffVarRealToGP
	
	subroutine CoeffVarRealToGPUseIndexStack( &
! Input
	  ThisCoeffVarReal, DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
! Output
	  OutputString)
! Writes coeff/var followed by its arguments
! [24/03/04] Add the possibility of a real here
! Input
	type (GPCoeffVarReal) :: ThisCoeffVarReal
	integer, intent(in) :: DimIndexStack, TopIndexStack
	character (len=*), intent(in) :: IndexStackSets(DimIndexStack)
	character(len=*), intent(in) :: IndexStackIndexes(DimIndexStack)
! Output
	character (len=*), intent(out) :: OutputString
! Local
	type (domain), pointer :: TheseArgs
	character (len=512) :: ArgString

	if(ThisCoeffVarReal%type.eq.'r') then
	  OutputString = ThisCoeffVarReal%name
	else
! Coeff or Variable
	  OutputString = ThisCoeffVarReal%name
	  if(ThisCoeffVarReal%type.eq.'c') then
! Upper case for Coefficients
	    call upper(OutputString)
	  end if
	  TheseArgs => ThisCoeffVarReal%arg
! Here need to look at index stack to see if take index from that
	  call ArgToGPUseIndexStack(TheseArgs, DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, ArgString)
	  if(ArgString.ne.'') then
	    OutputString = trim(OutputString)//'('//trim(ArgString)//')'
	  end if
	end if
	OutputString = trim (OutputString)

	return
	end subroutine CoeffVarRealToGPUseIndexStack

	subroutine CoeffVarToGP(ThisCoeffVar, OutputString)
! Writes coeff/var followed by its arguments
! Input
	type (GPCoeffVarReal) :: ThisCoeffVar
! Output
	character (len=*), intent(out) :: OutputString

! [24/03/04] Just call routine CoeffVarRealToGP
	call CoeffVarRealToGP(ThisCoeffVar, OutputString)

	return
	end subroutine CoeffVarToGP

	subroutine ArgToGP(TheseArgs, OutputString)
! Write TheseArgs in form suitable for GEMPACK. eg "s1,f1"
! No start "(" or end ")" is added here
! Input
	type (domain), pointer :: TheseArgs
! Output
	character (len=*), intent(out) :: OutputString
! Local
	integer NumArg
	type (domain), pointer :: CurrentArgument
	type (symbol), pointer :: CurrentSet
	character (len=128) CurrentIndex, CurrentAll

	OutputString = ''
	NumArg = 0 

	CurrentArgument => TheseArgs
	do while(associated(CurrentArgument))
	  if(NumArg.gt.0) then
! comma to separate arguments
	    OutputString = trim(OutputString)//','
	  end if
	  CurrentSet => CurrentArgument%s
	  call GPSet2Index(CurrentSet, CurrentIndex)
	  OutputString = trim(OutputString)//trim(CurrentIndex)
	  NumArg = NumArg + 1
	  CurrentArgument => CurrentArgument%next
	end do

	return
	end subroutine ArgToGP

	subroutine ArgToGPUseIndexStack( &
! Input
	  TheseArgs, DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
! Output
	  OutputString)
! Write TheseArgs in form suitable for GEMPACK. eg "s1,f1"
! No start "(" or end ")" is added here
! Input
	type (domain), pointer :: TheseArgs
	integer, intent(in) :: DimIndexStack, TopIndexStack
	character (len=*), intent(in) :: IndexStackSets(DimIndexStack)
	character(len=*), intent(in) :: IndexStackIndexes(DimIndexStack)
! Output
	character (len=*), intent(out) :: OutputString
! Local
	integer NumArg
	type (domain), pointer :: CurrentArgument
	type (symbol), pointer :: CurrentSet
	character (len=128) CurrentIndex, CurrentAll
	logical :: SetInIndexStack
	integer :: i

	OutputString = ''
	NumArg = 0 

	CurrentArgument => TheseArgs
	do while(associated(CurrentArgument))
	  if(NumArg.gt.0) then
! comma to separate arguments
	    OutputString = trim(OutputString)//','
	  end if
	  CurrentSet => CurrentArgument%s

! Need to see if this set is on the index stack. If so, use the index there.
	  SetInIndexStack = .false.
! [08/04/04] Go in REVERSE order, starting at the top of the index stack
	  do i=TopIndexStack,1,-1

!	    write(*,*)'ArgToGPUseIndexStack. DimIndexStack=',DimIndexStack,' I=',i
!	    write(*,*)'ArgToGPUseIndexStack. I=',i, ' IndexStackSets(I)=', IndexStackSets(i)
	 
	    if(.not.SetInIndexStack) then
	      if(EqualStringsIgnoreCase(CurrentSet%name, IndexStackSets(i))) then
	        SetInIndexStack = .true.
	        CurrentIndex = IndexStackIndexes(i)
	      end if
	    end if
	  end do

	  if(.not.SetInIndexStack) then
! [08/04/04] This is an error, I think
!WAS		[As before]
!WAS	    call GPSet2Index(CurrentSet, CurrentIndex)
	    call InternalErrorStop('ArgToGPUseIndexStack. '//CurrentSet%name//' is not in index stack.')
	  end if

	  OutputString = trim(OutputString)//trim(CurrentIndex)
	  NumArg = NumArg + 1
	  CurrentArgument => CurrentArgument%next
	end do

	return
	end subroutine ArgToGPUseIndexStack

	subroutine DeclareAllInThisGPCoeffMPSGEList(ThisGPCoeffMPSGEList)
! Input
	type (GPCoeffMPSGE), pointer :: ThisGPCoeffMPSGEList
! Local
	type (GPCoeffMPSGE), pointer :: CurrentGPCoeffMPSGE, GPCoeffMPSGEFound
	type (GPCoeffVarReal) :: NewGPCoeff
	logical :: Found

	CurrentGPCoeffMPSGE => ThisGPCoeffMPSGEList
	do while(associated(CurrentGPCoeffMPSGE))
! If not already declared, declare it
	  if(.not.HasBeenDeclaredGP('cs', CurrentGPCoeffMPSGE%Name)) then
	    call InitializeGPCoeffVarReal('c', NewGPCoeff)
	    NewGPCoeff%type = 'c'
	    NewGPCoeff%name = CurrentGPCoeffMPSGE%Name

! Arguments
! NO	    NewGPCoeff%arg => CurrentGPCoeffMPSGE%MaxArg
! Instead, find this in GPCoeffMPSGEList and use the arguments there - hopefully these are the
!  largest may need
	    call IsInGPCoeffMPSGEList(CurrentGPCoeffMPSGE%Name, Found, GPCoeffMPSGEFound)
	    if(Found) then
	      NewGPCoeff%arg => GPCoeffMPSGEFound%MaxArg
	    else
	      call InternalErrorStop( &
		'DeclareAllInThisGPCoeffMPSGEList. Expect to find '//trim(CurrentGPCoeffMPSGE%Name)// &
		' in GPCOeffMPSGEList.')
	    end if

	    NewGPCoeff%labelinfo = 'Occurs in an expression in MGE file'
	    NewGPCoeff%IsParam = .true.  ! ??
	    NewGPCoeff%IsGE0 = .false.  ! ??
!	    write(*,*)'DeclareAllInThisGPCoeffMPSGEList. Declaring ',trim(CurrentGPCoeffMPSGE%Name)
	    call DeclareGPCoeffVar(NewGPCoeff)
	  end if
	  CurrentGPCoeffMPSGE => CurrentGPCoeffMPSGE%next
	end do ! while(associated(ThisGPCOeffMPSGEList))

	return
	end subroutine DeclareAllInThisGPCoeffMPSGEList

	subroutine DoReadsAllInGPCoeffMPSGEList(ThisGPCoeffMPSGEList)
! Input
	type (GPCoeffMPSGE), pointer :: ThisGPCoeffMPSGEList
! Local
	type (GPCoeffMPSGE), pointer :: CurrentGPCoeffMPSGE
	type (GPCoeffVarReal) :: NewGPCoeff

	CurrentGPCoeffMPSGE => ThisGPCoeffMPSGEList
	do while(associated(CurrentGPCoeffMPSGE))
! If not already read, read it
	  call DoOneReadIfNotAlreadyDone(CurrentGPCoeffMPSGE%Name)
	  CurrentGPCoeffMPSGE => CurrentGPCoeffMPSGE%next
	end do ! while(associated(ThisGPCOeffMPSGEList))

	return
	end subroutine DoReadsAllInGPCoeffMPSGEList

	subroutine DeclareGPLevelsVar(ThisGPCoeff, ThisGPLinearVar)
! Declare a levels variable (ThisGPCoeff) with the name of the associated 
!  linear variable (ThisGPLinearVar) stated explicitly in the declaration
! Input
	type (GPCoeffVarReal), intent(in) :: ThisGPCoeff, ThisGPLinearVar
! Local
	type (field), pointer :: ThisField
	type (symbol), pointer :: ThisSymbol
	character (len=80) CoeffString, VarString, OutputString
	logical :: IsChangeVar, LinVarHasBeenDeclared
	logical ThisIsInGPCoeffMPSGEList, DoThisNow
	type(GPCoeffMPSGE), pointer :: GPCoeffMPSGEFound

! When GPCoeffMPSGEPass is true, only declare coefficients in GPCoeffMPSGEList
! When GPCoeffMPSGEPass is false, only declare coefficients not in GPCoeffMPSGEList
! Check this. Return if don't need to do this on this pass.
! [If do not check this now, the test about already having been declared will fail when
!  GPCoeffMPSGEPass is false.]
	call IsInGPCoeffMPSGEList(ThisGPCoeff%Name, ThisIsInGPCoeffMPSGEList, GPCoeffMPSGEFound)
	if(GPCoeffMPSGEPass) then
	  DoThisNow = ThisIsInGPCoeffMPSGEList
	else
	  DoThisNow = .not.ThisIsInGPCoeffMPSGEList
	end if
	if(.not.DoThisNow) Return		

	IsChangeVar = (ThisGPLinearVar%VarType.eq.'c')
! Add sign constraint if relevant
	if(ThisGPCoeff%IsGE0) then
	  OutputString = 'Variable(Levels, GE 0,'
	else
	  OutputString = 'Variable(Levels,'
	end if
	if(IsChangeVar) then
	  OutputString = trim(OutputString)//' Change,'
	end if
! Has this linear variable already been declared?
	LinVaRHasBeenDeclared = HasBeenDeclaredGP('vc', ThisGPLinearVar%name)
	if(LinVarHasBeenDeclared) then
!  Use Linear_Var=
	  OutputString = trim(OutputString)//' Linear_Var='//trim(ThisGPLinearVar%name)//')'
	else
!  Use Linear_Name=
	  OutputString = trim(OutputString)//' Linear_Name='//trim(ThisGPLinearVar%name)//')'
	end if

! Add the rest

	call newfield(ThisField)
	call newsymbol(ThisSymbol)
	ThisSymbol%name = ThisGPCoeff%name
	ThisField%ident => ThisSymbol

! Arguments
! If this is in GPCoeffMPSGEList, use the MaxArg there.
	if(ThisIsInGPCoeffMPSGEList) then
	  ThisField%arg => GPCoeffMPSGEFound%MaxArg
	else
	  ThisField%arg => ThisGPCoeff%arg
	end if

! If are declaring a levels variable, it is an internal error if this has already been declared as a Coefficient
	if (HasBeenDeclaredGP('cs',ThisGPCoeff%name)) then
	  call InternalErrorStop(trim(ThisGPCoeff%name)//' has already been declared as a Coefficient.'// &
	     '\n Here need to declare it as a Levels variable.')
	end if

! Declare it
	call DeclareFieldGP('c', OutputString, ThisField, ThisGPCoeff%labelinfo)

! Indicate that the linear variable has been declared
! [For the coefficient, this is done in routine DeclareFieldGP]
	if(.not.LinVarHasBeenDeclared) then
	  call AddGPDeclaration('vc', trim(ThisGPLinearVar%name))
	end if

	return
	end subroutine DeclareGPLevelsVar

	subroutine DeclareGPCoeffVar(ThisGPCoeffVar)
! Input
	type (GPCoeffVarReal), intent(in) :: ThisGPCoeffVar
! Local
	type (field), pointer :: ThisField
	type (symbol), pointer :: ThisSymbol
	character (len=80) CoeffVarString
	logical ThisIsInGPCoeffMPSGEList, DoThisNow
	type(GPCoeffMPSGE), pointer :: GPCoeffMPSGEFound

	call newfield(ThisField)
	call newsymbol(ThisSymbol)
!	write(*,*) 'DeclareGPCoeffVar. ThisGPCoeffVar%name is:', trim(ThisGPCoeffVar%name)
	ThisSymbol%name = ThisGPCoeffVar%name
	ThisField%ident => ThisSymbol

! Arguments
! If this is in GPCoeffMPSGEList, use the MaxArg there.
	call IsInGPCoeffMPSGEList(ThisGPCoeffVar%Name, ThisIsInGPCoeffMPSGEList, GPCoeffMPSGEFound)
	if(ThisIsInGPCoeffMPSGEList) then
	  ThisField%arg => GPCoeffMPSGEFound%MaxArg
	else
	  ThisField%arg => ThisGPCoeffVar%arg
	end if

	if(ThisGPCoeffVar%type.eq.'c') then
	  if(ThisGPCoeffVar%IsParam) then	  
	    CoeffVarString = 'Coefficient (Parameter)'
	  else
! Add sign constraint is relevant
	    if(ThisGPCoeffVar%IsGE0) then
	      CoeffVarString = 'Coefficient (GE 0)'
	    else
	      CoeffVarString = 'Coefficient'
	    end if
	  end if
	else if(ThisGPCoeffVar%type.eq.'v') then
	  if(ThisGPCoeffVar%OrigLevel.ne.' ') then
	    if(ThisGPCoeffVar%VarType.eq.'c') then
	      CoeffVarString = 'Variable (Change,Orig_Level='//trim(ThisGPCoeffVar%OrigLevel)//')'
	    else
	      CoeffVarString = 'Variable (Orig_Level='//trim(ThisGPCoeffVar%OrigLevel)//')'
	    end if
	  else
	    if(ThisGPCoeffVar%VarType.eq.'c') then
	      CoeffVarString = 'Variable (Change)'
	    else
	      CoeffVarString = 'Variable'
	    end if
	  end if
	else
	  call InternalErrorStop( &
	    'Unexpected value of ThisGPCoeffVar in routine DeclareGPCoeffVar. Value is: '//ThisGPCoeffVar%type)
	end if

	call DeclareFieldGP(ThisGPCoeffVar%type, CoeffVarString, ThisField, ThisGPCoeffVar%labelinfo)
 
	return
	end subroutine DeclareGPCoeffVar	

	subroutine DeclareFieldGP(CoeffVarType, DeclarationStart, ThisField, ThisLabellingInfo)
! Input
	character (len=*), intent(in) :: CoeffVarType ! either 'c' (Coeff) or 'v' (variable)
	character (len=*), intent(in) :: DeclarationStart  ! 'variable', 'coefficient' etc
!		DeclarationStart may contain qualifiers, eg (Parameter)
	type (field), pointer :: ThisField
	character (len=*), intent(in) :: ThisLabellingInfo
! Local
	character(len=512) OutputString, OutputStringAlls
	character(len=512) OutputStringArgs, CoeffVarName, ModDeclarationStart
	integer :: LenStart, LenSoFar, LenAlls
	character (len=3) TypeStart
	character (len=2) ThisType
	logical IsCoeff, ThisIsInGPCoeffMPSGEList, DoThisNow, ThisHasBeenDeclared
	integer :: MaxAllowedLength
	character (len=12) :: CoeffVarString
	type(GPCoeffMPSGE), pointer :: GPCoeffMPSGEFound

10005   format(a)
10017   format(2x,3a)

! [22/03/04] Are the next 2 lines about ThisField relevant now??
! If not associated, exit
	if(.not.associated(ThisField)) Return
! If identifier is not associated, exit
	if(.not.associated(ThisField%ident)) Return

! When GPCoeffMPSGEPass is true, only declare coefficients in GPCoeffMPSGEList
! When GPCoeffMPSGEPass is false, declare any not already declared.
!  [Coefficients occurring only in expressions in the MGE file are in GPCoeffMPSGEList but
!   will not be declared when GPCoeffMPSGEPass is true since they are only declared
!   via call to routine DeclareAllInThisGPCoeffMPSGEList, and this is only called
!   when GPCoeffMPSGEPass is false - see routine ConvertToGP.] 
! Check this. Return if don't need to do this on this pass.
	call IsInGPCoeffMPSGEList(ThisField%ident%name, ThisIsInGPCoeffMPSGEList, GPCoeffMPSGEFound)
	if(GPCoeffMPSGEPass) then
	  DoThisNow = ThisIsInGPCoeffMPSGEList
	else
	  ThisHasBeenDeclared = HasBeenDeclaredGP('cs', ThisField%ident%name)
	  DoThisNow = .not.ThisHasBeenDeclared
	end if
	if(.not.DoThisNow) Return		


! Use ModDeclarationStart in place of DeclarationStart since will modify
!  it when declaring a levels variable
	ModDeclarationStart = DeclarationStart

!  Set up IsCoeff and ThisType
	TypeStart = DeclarationStart
	call lower(TypeStart)
! If this is declaring a levels variable, write out DeclarationStart and
!  then proceed as if declaring a coefficient
	if(TypeStart.eq.'var' .and. index(DeclarationStart, '(Levels').gt.0) then
	  call WriteOneLineToTAB(DeclarationStart)
! Reset ModDeclarationStart in this case
	  ModDeclarationStart = ''
! Now proceed as if declaring a coefficient
	  TypeStart = 'coe'
	end if
	  
	IsCoeff = .false.
	if(TypeStart.eq.'coe') then
	  IsCoeff = .true.
	else if(TypeStart.eq.'var') then
	end if
	if (IsCoeff) then
	  ThisType = 'cs'
	else
	  ThisType = 'vc'
	end if

	if(CoeffVarType.eq.'c') then
	  MaxAllowedLength = llcs
	  CoeffVarString = 'Coefficient'
	  if(.not.IsCoeff) then
	    call InternalErrorStop('Routine DeclareFieldGP. CoeffVarType and IsCoeff mismatch')
	  end if
	else if(CoeffVarType.eq.'v') then
	  MaxAllowedLength = llvc
	  CoeffVarString = 'Variable'
	  if(IsCoeff) then
	    call InternalErrorStop('Routine DeclareFieldGP. CoeffVarType and IsCoeff mismatch')
	  end if
	end if

! If already declared, exit
! WAS	if (HasBeenDeclaredGPOld(ThisField%ident)) Return
	if (HasBeenDeclaredGP(ThisType,ThisField%ident%name)) Return

	LenStart = LEN_TRIM(ModDeclarationStart)

	OutputString = ''

	OutputString=trim(ModDeclarationStart)//' '
	LenSoFar = LenStart+1

	call ArgToAllsGP(ThisField%arg, OutputStringAlls)
	OutputStringAlls = trim(OutputStringAlls)
	LenAlls = LEN_TRIM(OutputStringAlls)
	if(OutputStringAlls.ne.'') then
! Output Start now if ncessary
	  if(LenStart.gt.25) then
	    call WriteOneLineToTAB(OutputString)
	    OutputString = ' '
	  end if
	  OutputString = trim(OutputString)//' '//OutputStringAlls
	end if
	LenSoFar = LEN_TRIM(OutputString)

! Output a line now if ncessary
	if(LenSoFar.gt.40) then
	  call WriteOneLineToTAB(OutputString)
	  OutputString = ' '
	end if

! The name
	CoeffVarName = ThisField%ident%name
!	write(*,*) 'DeclareFieldGP. ThisField%ident%name is:', trim(ThisField%ident%name)
! Stop if too long
	if(LEN_TRIM(CoeffVarName).gt.MaxAllowedLength) then
	    call ErrorStop('Sorry. Name "'//trim(CoeffVarName)// &
			'" is too long for a GEMPACK '//trim(CoeffVarString)//'.'// &
			'\n Please shorten it.') 
	end if
! Coefficients in upper case
	if(IsCoeff) then
	  call upper(CoeffVarName)
	end if
!	write(*,*)'ThisFile%ident%name): ', ThisField%ident%name
	OutputString = trim(OutputString)//' '//trim(CoeffVarName)
! The arguments
	if(OutputStringAlls.ne.'') then
! Opening (
	  OutputString = trim(OutputString)//'('
	end if
	call ArgToGP(ThisField%arg, OutputStringArgs)
	OutputString = trim(OutputString)//trim(OutputStringArgs)
	if(OutputStringAlls.ne.'') then
! Closing (
	  OutputString = trim(OutputString)//')'
	end if

! Labelling info and semicolon - on separate line - first output what we have
	call WriteOneLineToTAB(OutputString)
! Write the declaration
!	write(*,10017) 'Declaration: ', trim(OutputString)
! Labelling info and semicolon
	call PrepareLabelInfoForTABFile(ThisLabellingInfo, OutputString)
	OutputString = trim(OutputString)//' ;'
! Write to TAB file
	call WriteOneLineToTAB(OutputString)
! Mark this symbol as declared
! [15/03/04] No longer need this
!	call MarkAsDeclaredGP(ThisField%ident)
! Mark it in GPDeclarations
	call AddGPDeclaration(ThisType, trim(ThisField%ident%name))
 		
	return
	end subroutine DeclareFieldGP


	subroutine WriteNest(DescText, ThisNest)
	character*(*) DescText
	type (nest), pointer :: ThisNest
! Local
	type (netputlist), pointer :: elements
	type (netput), pointer :: ThisNetPut
	type (field), pointer :: IOField, qref, pref

10015   format(1x,a)

	elements => ThisNest%elements
	do while (associated(elements)) 
	  ThisNetPut => elements%np
	  IOField => ThisNetPut%f   ! I: or O: field
!	  if (ThisNetPut%output) then
!	    write(*,10015) ' An output'
!	  else
!	    write(*,10015) ' An input'
!	  end if
	  qref => ThisNetPut%qref
	  pref => ThisNetPut%pref

	  call WriteField('IOField', IOField)
	  if(associated(IOField)) then
!	    call DeclareFieldGP('Variable', IOField)
	  end if

	  call WriteField('QREF', qref)
	  if(associated(qref)) then
!	    call DeclareFieldGP('Coefficient', qref)
	  end if
	  call WriteField('PREF', pref)
	  if(associated(pref)) then
!	    call DeclareFieldGP('Coefficient', pref)
	  end if
	  elements => elements%next
	end do
	
	return
	end subroutine WriteNest

!!	Allocate a new GPDeclaration and assign default values
!!	for all the characteristics

	subroutine NewGPDeclaration(ThisGPDeclaration)
	type (GPDeclaration), pointer :: ThisGPDeclaration
	nullify(ThisGPDeclaration)
	allocate(ThisGPDeclaration)
	ThisGPDeclaration%type = ''  ! impossible type
	ThisGPDeclaration%name = ''  ! impossible name
	nullify(ThisGPDeclaration%next)
	return
	end subroutine NewGPDeclaration

!! Introduce a new GPDeclaration in the master list.

        subroutine AddGPDeclaration(type, name)      

        character (len=*), intent(in) :: type
        character (len=*), intent(in) :: name

        type (GPDeclaration), pointer :: ThisGPDeclaration

!	write(*,*)'AddGPDeclaration: type=', type

        if (.not.associated(GPDeclarationList)) then
!	  write(*,*)'AddGPDeclaration: not associated'
	  call NewGPDeclaration(GPDeclarationList)
          ThisGPDeclaration => GPDeclarationList
        else
!	  write(*,*)'AddGPDeclaration: is associated'
	  call NewGPDeclaration(GPDeclarationLast%next)
          ThisGPDeclaration => GPDeclarationLast%next
        end if
        ThisGPDeclaration%type = type
        ThisGPDeclaration%name = name
        nullify(ThisGPDeclaration%next)
        GPDeclarationLast => ThisGPDeclaration
        return
        end subroutine AddGPDeclaration

	logical function HasBeenDeclaredGP(type, name)
! Tells if this has already been declared
! Input
        character (len=*), intent(in) :: type
        character (len=*), intent(in) :: name
! Local
	type (GPDeclaration), pointer :: CurrentGPDeclaration
	character(len=2) CurrentType, TestType
	character(len=LengthGPDeclarationName) CurrentName, TestName

	HasBeenDeclaredGP = .false.

	TestType = type
	call lower(TestType)
! Expect Type to be either 'cs' [coeff] or 'vc' [variable]
	if(TestType.ne.'cs'.and.TestType.ne.'vc') then
	  call InternalErrorStop('HasBeenDeclared. Unexpected TestType:'//trim(TestType))
	end if
	TestName = trim(name)
	call lower(TestName)

! Run throught the list of declarations seeking a match
	CurrentGPDeclaration => GPDeclarationList
	do while(associated(CurrentGPDeclaration))
	  CurrentType = CurrentGPDeclaration%type
!	  write(*,*)'HasBeenDeclaredGP: CurrentType=', CurrentType
	  call lower(CurrentType)
	  CurrentName = CurrentGPDeclaration%name
	  CurrentName = trim(CurrentName)
!	  write(*,*)'HasBeenDeclaredGP: CurrentName=', CurrentName
	  call lower(CurrentName)
	  if(CurrentName.eq.TestName) then
	    if(CurrentType.eq.TestType) then
	      HasBeenDeclaredGP = .true.
	      return
! [26/04/04] I don't see that this is an internal error, so suppress it.
!  For example, see the calls to this routine in routine DoConstraints where
!  are trying to see if a string has been declared and are not wanting to
!   check if it would be a coeff or a var if declared. 
!NO	    else
!NO		write(*,*)'CurrentName=',trim(CurrentName)
!NO		write(*,*)'CurrentType=',trim(CurrentType),' TestType=',trim(TestType)
!NO		call InternalErrorStop('HasBeenDeclared. Names equal but not types.')
	    end if
	  end if
	  CurrentGPDeclaration => CurrentGPDeclaration%next
	end do	
	
	return
	end function HasBeenDeclaredGP

	subroutine WriteExogenousListOnCMF

	type (GPName), pointer :: CurrentGPName
	character (len=512) :: OutputString

! temporary
!	call WriteGPNameList

	write(iocmfgp, '(a)') ' '
	write(iocmfgp, '(a)') '! Closure '
	write(iocmfgp, '(a)') '! ------- '
	write(iocmfgp, '(a)') '! '

! Go through GPNameList and build up list of all that are exogenous
	OutputString = 'exogenous'
	CurrentGPName => GPNameList
	do while(associated(CurrentGPName))
	  if(CurrentGPName%type.eq.'v') then
	    if(CurrentGPName%ExogEndogStatus.eq.'x') then
! Add this to the list
	      if(LEN_TRIM(OutputString).gt.60) then
		  write(iocmfgp,'(a)') trim(OutputString)
	          OutputString = ' '
	      end if
	      OutputString = trim(OutputString)//' '//CurrentGPName%name
	    end if
	  end if

	  CurrentGPName => CurrentGPName%next
	end do ! while(associated(CurrentGPName))

! Complete the list
	OutputString = trim(OutputString)//' ;'
	write(iocmfgp,'(a)') trim(OutputString)

	write(iocmfgp,'(a)') 'Rest endogenous ;'

	return
	end subroutine WriteExogenousListOnCMF

	subroutine WriteCMFFile

! Local
	character (len=512) :: OutputString, TempString

	write(iocmfgp, '(a)') 'Auxiliary files = '//trim(tabfileroot)//' ;'

! Are there any reads - if not, do not need input or updated har file
	if(NumGPReads.gt.0) then
	  write(iocmfgp, '(a)') 'File Input = '//trim(tabfileroot)//'.har ;'
! Use "<CMF>" for updated file name
! WAS	write(iocmfgp, '(a)') 'Updated File Input = '//trim(tabfileroot)//'.upd ;'
	  write(iocmfgp, '(a)') 'Updated File Input = <cmf>.upd ;'
	end if ! if(NumGPReads.gt.0) then

	write(iocmfgp, '(a)') 'Extrapolation Accuracy File = yes ;'
	write(iocmfgp, '(a)') 'Log File = yes ;'
	write(iocmfgp, '(a)') 'Method = Euler ;  ! or Gragg'
	write(iocmfgp, '(a)') 'Steps = 4 6 8 ;  ! change as needed'
	write(iocmfgp, '(a)') '! Use more than one subinterval if an assertion fails'
	write(iocmfgp, '(a)') '!  after the first step. [That failure probably means that'
	write(iocmfgp, '(a)') '!  you need to solve the model more accurately, which is what'
	write(iocmfgp, '(a)') '!  happens if you use several subintervals. Increase the number'
	write(iocmfgp, '(a)') '!  of subintervals if necessary.] To use more than one subinterval,'
	write(iocmfgp, '(a)') '!  remove the "!" at the start of the next line.'
	write(iocmfgp, '(a)') '!Subintervals = 3 ;'

! Write the Closure to CMF file
	call WriteExogenousListOnCMF

	write(iocmfgp, '(a)') ' '
	write(iocmfgp, '(a)') '! Shocks '
	write(iocmfgp, '(a)') '! ------ '
	if(WalrasNumeraireString.ne.' ') then
! Have found market to omit. Shock its price as a homogeneity simulation
	  write(iocmfgp, '(a)') '! Next is a shock to the market price in the omitted market.'
	  write(iocmfgp, '(a)') '! Hence this simulation is a nominal homogeneity simulation.'
	  write(iocmfgp, '(a)') '! [All prices and dollar values should increase by 1% and'
	  write(iocmfgp, '(a)') '!   all quantities should stay unchanged.]'
	  write(iocmfgp, '(a)') ' '
	  write(iocmfgp, '(a)') 'Shock '//trim(WalrasNumeraireString)//' = 1 ;'
	else
! Did not find equation to omit. Warn the user. [Also put warning in Command file.]
	  write(iocmfgp, '(a)') '! Sorry, the program did not identify an equation to omit to'
	  write(iocmfgp, '(a)') '! satisfy Walras law. You will need to modify the TAB file'
	  write(iocmfgp, '(a)') '! to omit one equation.'
	  write(iocmfgp, '(a)') '! You cannot carry out a simulation until you have done this.'
	  write(iocmfgp, '(a)') '! [This is why no shocks have been specified here.]'
	end if

	write(iocmfgp, '(a)') ' '
	write(iocmfgp, '(a)') '! Verbal Description '
	write(iocmfgp, '(a)') '! ------------------ '
	write(iocmfgp, '(a)') 'Verbal Description = '
	if(WalrasNumeraireString.ne.' ') then
! Have found market to omit. Shock its price as a homogeneity simulation
	  write(iocmfgp, '(a)') ' Nominal homogeneity simulation, shocking '//trim(WalrasNumeraireString)
	else
	  write(iocmfgp, '(a)') '! [Please add it here (can be several lines)]'
	end if
	write(iocmfgp, '(a)') '  ;  ! End of Verbal Description'

	return
	end subroutine WriteCMFFile

	subroutine WriteTABSTIFile

! Local
	character (len=512) :: OutputString, TempString

	write(iotabstigp, '(a)') 'bat'
	write(iotabstigp, '(a)') 'acd'   ! always change differentiation of levels equations(?)
	write(iotabstigp, '(a)') ' '
	write(iotabstigp, '(a)') trim(tabfileroot)
	write(iotabstigp, '(a)') ' '
	write(iotabstigp, '(a)') 'a'    ! go to code
	write(iotabstigp, '(a)') 'pgs'    ! output for GEMSIM
	write(iotabstigp, '(a)') ' '
	write(iotabstigp, '(a)') ' '

	return
	end subroutine WriteTABSTIFile

	subroutine DoConstraints
! Run through the constraints, adding the appropriate equations to TAB file

! Local
	type(function), pointer :: CurrentFunction
	type(record), pointer :: CurrentRecord, SecondRecord
	type(functionGP), pointer :: CurrentFunction2GP
	type (endowmentGP), pointer :: CurrentEndowment2GP
	type (netputGP), pointer :: CurrentNetput2GP
	type (taxGP), pointer :: CurrentTax2GP
	type(field), pointer :: FirstField, SecondField
	integer :: NumFuncDone, NumELinesDone, NumConstraintsDone, kpass, NumIOLinesDone, CurrentTaxNumber
	character (len=128) :: ConstraintVariableName, ConstraintAbbreviation
	character (len=128) :: EquationStart, OutputString, ThisName
! auxiliary variable can occur in r: field or n: field
	type (GPCoeffVarReal) :: CurrentRNFieldCoeff, ConstraintRNFieldVar, ConstraintRNFieldCoeff
	logical :: RelevantELineFound, IsLinear, IsLevels, FoundSecondRecord, RelevantIOLineFound
        character (len=2048) :: SecondRecordText, ThisGPExpression  ! Input records are limited to 2048 characters
	character (len=256) :: OutputStringAlls
	type(GPCoeffMPSGE), pointer :: GPCoeffMPSGEHere, ThisGPCoeffMPSGEHere
	type (symbol), pointer :: ThisSymbol
	type (GPCoeffVarReal) :: NewGPCoeff
	logical :: NameKnown, NameKnown1, NameKnown2
	integer :: StartPos

	NumFuncDone = 0
	NumConstraintsDone = 0
	CurrentFunction => functionlist
	do while(associated(CurrentFunction))
	  CurrentRecord => CurrentFunction%firstrecord
	  FirstField => CurrentRecord%firstfield
	  NumFuncDone = NumFuncDone + 1
	  if(EqualStringsIgnoreCase(FirstField%label,'$constraint')) then
!	    write(*,*)'Found $constraint:'//trim(FirstField%data)
	    ConstraintVariableName = FirstField%identtext
!	    write(*,*)'ConstraintVariabelName is:'//trim(ConstraintVariableName)
	    ConstraintAbbreviation = trim(FirstField%label)//':'//trim(FirstField%data)

!  Re-initialize 'pre' messages again at start of each function
	    call InitializeMessages('pre',0)
	    Messages%PreLine(1) = 'Processing '//trim(ConstraintAbbreviation)
! Echo this function so user sees progress
	    if(EchoMainProgressGP) then
	      write(*,'(2x,a)') trim(Messages%PreLine(1))
	    end if

! [09/06/04] At present do not handle exceptions on a demand block
	    if(CurrentFunction%firstrecord%firstfield%condtn.ne.' ') then
	      call ErrorStop('Sorry. At present this program cannot handle exceptions on $constraint: blocks')
	    end if

!----------------------------------------------------------------------------------------
! Need to find this variable in an r: field in an e: line, or in an n: field in an o: or i: line
! [03/06/04] Laurent tells me this is not necessary. An auxiliary variable can be declared
!   and only occur after a $constraint:
!  So I suppressed the error at the end of this testing.
	    RelevantELineFound = .false.
	    RelevantIOLineFound = .false.
	    CurrentFunction2GP => FunctionGPList
	    do while(associated(CurrentFunction2GP).and.(.not.RelevantELineFound).and.(.not.RelevantIOLineFound))

	      if(CurrentFunction2GP.IsDemandFunctionGP) then
! Try to find it in an r: field in an e: line
		NumELinesDone = 0
		CurrentEndowment2GP => CurrentFunction2GP%FirstEndowmentGP
		do while(NumELinesDone.lt.CurrentFunction2GP%NumEFields.and. .not.RelevantELineFound)
		  if(CurrentEndowment2GP%HasRField) then
		    CurrentRNFieldCoeff = CurrentEndowment2GP%EndowRFieldCoeff
		    if(EqualStringsIgnoreCase(CurrentRNFieldCoeff%name,ConstraintVariableName)) then
		      ConstraintRNFieldVar = CurrentEndowment2GP%EndowRFieldVar
		      ConstraintRNFieldCoeff = CurrentEndowment2GP%EndowRFieldCoeff
		      RelevantELineFound = .true.
		    end if
		  end if ! if(CurrentEndowment2GP%HasRField) then
		  NumELinesDone = NumELinesDone + 1
		  CurrentEndowment2GP => CurrentEndowment2GP%next
		end do ! while(NumELinesDone.lt.CurrentFunction2GP$NumEFields)
	      end if ! if(CurrentFunction2GP.IsDemandFunction) then

	      if(CurrentFunction2GP.IsProdFunctionGP) then
! Try to find it in an n: field in an o: or i: line
		NumIOLinesDone = 0
		CurrentNetput2GP => CurrentFunction2GP%FirstNetputGP
		do while(NumIOLinesDone.lt.(CurrentFunction2GP%NumIFields+CurrentFunction2GP%NumOFields).and. .not.RelevantIOLineFound)

		  if(CurrentNetput2GP.NumTaxTypes.gt.0) then
! Run through the taxes
		    CurrentTax2GP => CurrentNetput2GP%FirstTaxGP
		    CurrentTaxNumber = 0
		    do while(CurrentTaxNumber.lt.CurrentNetput2GP%NumTaxTypes)
		      if(CurrentTax2GP%HasNField) then
		        CurrentRNFieldCoeff = CurrentTax2GP%NFieldCoeff
		        if(EqualStringsIgnoreCase(CurrentRNFieldCoeff%name,ConstraintVariableName)) then
		          ConstraintRNFieldVar = CurrentTax2GP%NFieldVar
		          ConstraintRNFieldCoeff = CurrentTax2GP%NFieldCoeff
		          RelevantIOLineFound = .true.
		        end if
		      end if ! if(CurrentNetput2GP%HasNField) then
		      CurrentTaxNumber = CurrentTaxNumber + 1
		      CurrentTax2GP => CurrentTax2GP%next
		    end do ! do while(CurrentTaxNumber.lt.CurrentNetput2GP%NumTaxTypes)
		  end if ! if(CurrentNetput2GP.NumTaxTypes.gt.0) then
		  NumIOLinesDone = NumIOLinesDone + 1
		  CurrentNetput2GP => CurrentNetput2GP%next
		end do ! do while(NumIOLinesDone.lt.(CurrentFunction2GP%NumIFields+CurrentFunction2GP%NumOFields).and. .not.RelevantELineFound)
	      end if ! if(CurrentFunction2GP.IsProdFunction) then

	      CurrentFunction2GP => CurrentFunction2GP%next
	    end do ! do while(associated(CurrentFunction2GP).and.(.not.RelevantELineFound).and.(.not.RelevantIOLineFound))

	    if(.not.RelevantELineFound .and. .not.RelevantIOLineFound) then
! [03/06/04] Laurent tells me this is not necessary. An auxiliary variable can be declared
!   and only occur after a $constraint:
!  So I have suppressed this error message.
!.NO	      call InternalErrorStop('Did not find variable after : in "'//trim(ConstraintAbbreviation)//'" in an r:  or n: field')
	    end if ! if(.not.RelevantElineFound) then

! End of (now unnecessary) section trying to find this auxiliary
!    variable in an r: field in an e: line, or in an n: field in an o: or i: line
!----------------------------------------------------------------------------------------

	    NumConstraintsDone = NumConstraintsDone + 1

	    if(NumConstraintsDone.eq.1) then
! Heading
	      call WriteOneLineToTAB(' ')
	      call WriteOneLineToTAB('![[! The $constraint Equations !]]!')
	    end if

! Echo the $constraint line to TAB file
	    call WriteOneLineToTAB(' ')
	    OutputString = '! $constraint:'//trim(FirstField%data)//' !'	    
	    call WriteOneLineToTAB(OutputString)

! [14/04/04] Change to use the method recommended by Tom Rutherford
! Add the constraint equation to the TAB file
! Go through the records in this function.

! [26/04/04] Do two passes. When KPASS=1, declare and read values of any coeffs
!  appearing for the first time in this equation. When KPASS=2, write the equation.
	   do kpass=1,2

! Reset CurrentRecord at start of each KPASS
	    CurrentRecord => CurrentFunction%firstrecord

	    FoundSecondRecord = .false.
	    do while(associated(CurrentRecord%next))
	      CurrentRecord => CurrentRecord%next
	      if(CurrentRecord%line%text(1:1).eq.'*') cycle  ! line is a comment
	      if(CurrentRecord%line%text.eq.' ') cycle  ! line is all blank
	      if(.not.FoundSecondRecord) then
	        FoundSecondRecord = .true.
		SecondRecord => CurrentRecord
		SecondRecordText = SecondRecord%line%text 
!	        write(*,*)'SecondRecordText is:', trim(SecondRecordText)
! remove blanks and TABs at start of SecondRecordText
		do while(SecondRecordText(1:1).eq.' '.or.SecondRecordText(1:1).eq.CHAR(9))
		  SecondRecordText = SecondRecordText(2:)
		end do ! while(SecondRecordText(1:1).eq.' ')
! [05/06/04] If SecondRecordText begins with "(linear)" then is a linear equation.
!  Otherwise it is a levels equation and may need to change variables in the MGE file to
!   their GEMPACK levels forms (eg add _L to end of $commodities)
	        IsLinear = EqualStringsIgnoreCase(SecondRecordText(1:8), '(linear)')	
!OLD	        IsLevels = EqualStringsIgnoreCase(SecondRecordText(1:8), '(levels)')
	        IsLevels = .not.IsLinear
	        if(IsLinear) then
		  EquationStart = 'Equation (Linear)'
	        else if(IsLevels) then
		  EquationStart = 'Equation (Levels)'
!OLD	        else
!OLD		  call ErrorStop('Expect "(Linear)" or "(Levels)" at start of $constraint equation')
	        end if
		if(kpass.eq.2) then
! Only write equation when KPASS=2
	          OutputString = trim(EquationStart)//' E_'//trim(ConstraintVariableName)
! Write this line
	          call WriteOneLineToTAB(OutputString)
! Quantifiers - take them from the $constraint variable
		  call ArgToAllsGP(FirstField%arg, OutputStringAlls)
		  if(OutputStringAlls.ne.' ') then
	            call WriteOneLineToTAB(' '//OutputStringAlls)
		  end if
		end if ! if(kpass.eq.2) then
! Write the rest this equation
! Need to convert it from GAMS syntax to GEMPACK syntax
		if(IsLinear) then
		  StartPos = 9
		else
		  StartPos = 1
		end if

! [09/06/04] At present cannot handle $ exceptions in the constraint equations. Test and record
!   error if one is present
		if(index(SecondRecordText(StartPos:),'$').gt.0) then
		  call ErrorStop('Sorry. At present, this program cannot handle "$" exceptions in constraint equations')
		end if
 
	        ThisGPExpression = ExpressionToGPSyntax2(SecondRecordText(StartPos:), &
		  .false., ' ', IsLevels, GPCoeffMPSGEHere)
	        if(kpass.eq.2.and.ThisGPExpression.ne.' ') then
	          call WriteOneLineToTAB('  '//ThisGPExpression)
	        end if

!	       End "if(.not.FoundSecondRecord) then"
	      else

! Write the rest of the equation as in the MGE file - skip (linear) or (levels)
! [09/06/04] At present cannot handle $ exceptions in the constraint equations. Test and record
!   error if one is present
		if(index(CurrentRecord%line%text,'$').gt.0) then
		  call ErrorStop('Sorry. At present, this program cannot handle "$" exceptions in constraint equations')
		end if

! Need to convert it from GAMS syntax to GEMPACK syntax
	        ThisGPExpression = ExpressionToGPSyntax2(CurrentRecord%line%text, &
		  .false., ' ', IsLevels, GPCoeffMPSGEHere)


	        if(kpass.eq.2.and.ThisGPExpression.ne.' ') then
	          call WriteOneLineToTAB('  '//ThisGPExpression)
	        end if

	      end if ! if(.not.FoundSecondRecord) then..else..

!-------------------------------------------------------------------------------------
	      if(kpass.eq.1) then

! [26/04/04] Run through GPCoeffMPSGEHere. Anything here which is not a central variable
!  must be a Coefficient(parameter). May need to declare it and read its values (if not already
!  declared or read).
		  ThisGPCoeffMPSGEHere => GPCoeffMPSGEHere
		  do while(associated(ThisGPCoeffMPSGEHere))
! Is this a central variable, or related to one?
! The constraint equation can be a linear or a levels one.
! The $sectors and $commodities are linear variables. Each has <name>_L levels variable associated.
! The $consumers are linear variables.
! The $auxiliaries are levels variables. Each has linear change variable c_<name> associated.
! All of these variables should have been declared already. So just test this.
		    ThisName = ThisGPCoeffMPSGEHere%name
!		    write(*,*)'DoConstraints. ThisName = ', trim(ThisName)
		    NameKnown1 = HasBeenDeclaredGP('cs', ThisName)
		    NameKnown2 = HasBeenDeclaredGP('vc', ThisName)
		    NameKnown = NameKnown1.or.NameKnown2
		    if(.not.NameKnown) then
! This has not been declared
! This should be a Coefficient. Declare it since has not already been declared. And read its values.
		        call InitializeGPCoeffVarReal('c', NewGPCoeff)
		        NewGPCoeff%type = 'c'
		        NewGPCoeff%name = ThisGPCoeffMPSGEHere%Name
! Arguments
!**********************************************************************
! [26/04/04] At present this coeff may not be in GPCoeffMPSGEList (though could probably
!  ensure that those occurring in $constraint get into that list. So hope that
!   ths arguments we see here are what we need when declaring the coeff.
! [This may fail if coeff occurs in different $constraints with args ranging
!   over different sets - then would need to add to GPCoeffMPSGEList and use max
!    args found.]
		        NewGPCoeff%arg => ThisGPCoeffMPSGEHere%MaxArg
!LATER? Instead, find this in GPCoeffMPSGEList and use the arguments there - hopefully these are the
!LATER?  largest may need
!LATER?	    call IsInGPCoeffMPSGEList(ThisGPCoeffMPSGEHere%Name, Found, GPCoeffMPSGEFound)
!LATER?	    if(Found) then
!LATER?	      NewGPCoeff%arg => GPCoeffMPSGEFound%MaxArg
!LATER?	    else
!LATER?	      call InternalErrorStop( &
!LATER?		'DeclareAllInThisGPCoeffMPSGEList. Expect to find '//trim(ThisGPCoeffMPSGEHere%Name)// &
!LATER?		' in GPCOeffMPSGEList.')
!LATER?	    end if
!**********************************************************************
	
		        NewGPCoeff%labelinfo = 'Occurs in $constraint:'//trim(FirstField%data)
		        NewGPCoeff%IsParam = .true.  ! ??
		        NewGPCoeff%IsGE0 = .false.  ! ??
!		        write(*,*)'DoConstraints. Declaring ',trim(ThisGPCoeffMPSGEHere%Name)
		        call DeclareGPCoeffVar(NewGPCoeff)
! Read its values - can't have been read before since it hasn't been declared before
			call DoOneReadIfNotAlreadyDone(ThisName)
		
		    end if ! if(.not.NameKnown) then

		    ThisGPCoeffMPSGEHere => ThisGPCoeffMPSGEHere%next
		  end do ! do while(associated(ThisGPCoeffMPSGEHere))

	      end if ! if(kpass.eq.1) then
!-------------------------------------------------------------------------------------

	    end do ! while(associated(CurrentRecord%next))

	   end do ! do kpass=1,2

	    if(.not.FoundSecondRecord) then
! No equation is present - a user error
	      call ErrorStop('There is no equation after $constraint:'//trim(FirstField%data)) 
	    end if ! if(.not.FoundSecondRecord) then

! The old way
! Add the constraint equation to the TAB file
!OLD	    SecondField => CurrentRecord%next%firstfield
!OLD	    write(*,*)'SecondField%label is:', trim(SecondField%label)
!OLD	    write(*,*)'SecondField%data is:', trim(SecondField%data)
!OLD	    SecondRecord => CurrentRecord%next
! Expect SecondField%data to begin "(linear)" or "(levels)"
!OLD	    IsLinear = EqualStringsIgnoreCase(SecondField%data(1:8), '(linear)')	
!OLD	    IsLevels = EqualStringsIgnoreCase(SecondField%data(1:8), '(levels)')
!OLD	    if(IsLinear) then
!OLD		EquationStart = 'Equation (Linear)'
!OLD	    else if(IsLevels) then
!OLD		EquationStart = 'Equation (Levels)'
!OLD	    else
!OLD		call ErrorStop('Expect "(Linear)" or "(Levels)" at start of $constraint equation')
!OLD	    end if
!OLD	    OutputString = trim(EquationStart)//' E_'//trim(ConstraintVariableName)
! Write this line
!OLD	    call WriteOneLineToTAB(OutputString)
! Write the rest of the equation exactly as in the MGE file - skip (linear) or (levels)
!OLD	    OutputString = SecondField%data(9:)
!OLD	    call WriteOneLineToTAB(OutputString)


! Mark the auxiliary variable as endogenous
!	    write(*,*)'DoConstraints. Marking as endog ',trim(ConstraintRNFieldVar%name)
	    call MarkAsEndogenous(ConstraintRNFieldVar)

	  end if ! if(EqualStringsIgnoreCase(FirstField%label,'$constraint')) then

	  CurrentFunction => CurrentFunction%next
	end do  ! while(associated(CurrentFunction))

!  Re-initialize 'pre' messages again at start of each function
	call InitializeMessages('pre',0)

	return
	end subroutine DoConstraints

	subroutine OmitAllOfSpecifiedString(SpecString, InputOutputString)
! Input
	character (len=*), intent(in) :: SpecString
! Input and output
	character (len=*) :: InputOutputString
! Local
	integer CurrentLength, n1, LenStringOmitting, end1pos, st2pos

	LenStringOmitting = LEN_TRIM(SpecString)
12	continue
	CurrentLength = LEN_TRIM(InputOutputString)
	n1 = INDEX(InputOutputString, SpecString)
	if(n1.gt.0) then
! END1POS is end of first string left after make this omission
	  end1pos=n1-1
! ST2POS is start of second string left after make this omission
	  st2pos=n1+LenStringOmitting
	  if(end1pos.ge.1.and.st2pos.le.CurrentLength) then
	    InputOutputString = InputOutputString(1:end1pos)//InputOutputString(st2pos:)
	  else if(end1pos.le.0.and.st2pos.le.CurrentLength) then
	    InputOutputString = InputOutputString(st2pos:)
	  else if(end1pos.ge.1.and.st2pos.gt.CurrentLength) then
	    InputOutputString = InputOutputString(1:end1pos)
	  else
	    InputOutputString = ''
	  end if
! Do it again
	  goto 12
	end if
	 
	return
	end subroutine OmitAllOfSpecifiedString

	character (len=1024) function ExpressionToGPSyntax(GAMSStyleExpression, GPCoeffMPSGEHere)
! This forms up GP-style expression as the value of the function.
! This also puts all GPCoeffMPSGEs in the expression into GPCoeffMPSGEHere (a list of GPCoeffMPSGEs).
! Input
	character (len=*) :: GAMSStyleExpression
! Output
! Note that the MaxArg part of things in GPCoeffMPSGEHere are not set up, just the name part of the
!  Symbol part is set up 
	type (GPCoeffMPSGE), pointer :: GPCoeffMPSGEHere ! Pointer to first in list of all GPCoeffMPSGE in this expression

! Call ExpressionToGPSyntax2
	ExpressionToGPSyntax = ExpressionToGPSyntax2(GAMSStyleExpression, .false., ' ', .false., GPCoeffMPSGEHere)
	return
	end function ExpressionToGPSyntax
	
	character (len=1024) function ExpressionToGPSyntax2( &
! Input
	  GAMSStyleExpression, CompleteLogicalExpression, CompletionStringForLogicalExpression, &
	  ConvertCommodityEtcNamesToLevels, &
! Output
	  GPCoeffMPSGEHere)

! Input
	character (len=*), intent(in) :: GAMSStyleExpression
	logical, intent(in) :: CompleteLogicalExpression
	character (len=*), intent(in) :: CompletionStringForLogicalExpression
	logical, intent(in) :: ConvertCommodityEtcNamesToLevels
! Output
! Note that the MaxArg part of things in GPCoeffMPSGEHere are not set up, just the name part of the
!  Symbol part is set up 
	type (GPCoeffMPSGE), pointer :: GPCoeffMPSGEHere ! Pointer to first in list of all GPCoeffMPSGE in this expression

! Local
	integer, parameter :: DimIndexStack=1
	integer :: TopIndexStack
	character(len=llst) :: IndexStackSets(DimIndexStack)
	character(len=llindex) :: IndexStackIndexes(DimIndexStack)
	logical, parameter :: UseIndexStack=.false.

! Call ExpressionToGPSyntax3 (which has index stack, not used here)

	ExpressionToGPSyntax2 = ExpressionToGPSyntax3( &
	  GAMSStyleExpression, CompleteLogicalExpression, CompletionStringForLogicalExpression, &
	  ConvertCommodityEtcNamesToLevels, &
! [03/06/04] Add UseIndexStack and IndexStack stuff
	  UseIndexStack, DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
! Output
	  GPCoeffMPSGEHere)

	return
	end function ExpressionToGPSyntax2

	character (len=1024) function ExpressionToGPSyntax3( &
! Input
	  GAMSStyleExpression, CompleteLogicalExpression, CompletionStringForLogicalExpression, &
	  ConvertCommodityEtcNamesToLevels, &
! [03/06/04] Add UseIndexStack and IndexStack stuff
	  UseIndexStack, DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
! Output
	  GPCoeffMPSGEHere)
! This forms up GP-style expression as the value of the function.
! This also puts all GPCoeffMPSGEs in the expression into GPCoeffMPSGEHere (a list of GPCoeffMPSGEs).
! Input
	character (len=*), intent(in) :: GAMSStyleExpression
	logical, intent(in) :: CompleteLogicalExpression
	character (len=*), intent(in) :: CompletionStringForLogicalExpression
	logical, intent(in) :: ConvertCommodityEtcNamesToLevels
	logical, intent(in) :: UseIndexStack
	integer, intent(in) :: DimIndexStack, TopIndexStack
	character (len=*), intent(in) :: IndexStackSets(DimIndexStack)
	character(len=*), intent(in) :: IndexStackIndexes(DimIndexStack)
! Output
! Note that the MaxArg part of things in GPCoeffMPSGEHere are not set up, just the name part of the
!  Symbol part is set up 
	type (GPCoeffMPSGE), pointer :: GPCoeffMPSGEHere ! Pointer to first in list of all GPCoeffMPSGE in this expression
! Local
	character (len=1024) :: TempString1, TempString2, OutputString, ThisWord, NewWord, ThisWord2
	character (len=1024) :: ThisIndex, LastWord, CurrentCoeffName, OutputText
	integer :: LenOutputString, StartPos, TrueStart, TrueEnd, llen, WordLength, TrueStart2, TrueEnd2
	integer :: NextArgumentNumber, LenOutput
	logical :: Found, Found2, Finished, StartingSum, WordProcessed, BracketAfterSum, JustFoundCoeff
	logical :: InsideCoeffArguments, IndexAfterSum
	type (GPCoeffMPSGE), pointer :: NewGPCoeffMPSGE, GPCoeffMPSGEHereLast, GPCoeffMPSGECurrentCoeff
	type (GPCoeffMPSGE), pointer :: GPCoeffMPSGEFound
	type (symbol), pointer :: ThisSetSymbol
! For completing a logical expression - use value type stack
	integer, parameter :: MaxValueTypeStack = 100
	integer, dimension (MaxValueTypeStack) :: ValueTypeStack
! States are 21:Expect value, 22: Expect arithmetic (or logical) operator
!		31:Expect ( after "sameas"
!		32:Expect first index after "sameas"
!		33:Expect , after "sameas"
!		34:Expect second index after "sameas"
!		35:Expect ) to end "sameas"

	integer :: TopValueTypeStack, State, OrigState
	logical :: FoundSameAs, ans1, ans2, ans3
	character (len=20) :: TypeFound

	OutputString = ''
	LenOutputString = 0
	TopValueTypeStack = 0
	State = 21

	llen = LEN_TRIM(GAMSStyleExpression)
!	write(*,*)'GAMSStyleExpression is:', trim(GAMSStyleExpression)

	nullify(GPCoeffMPSGEHere)
	nullify(GPCoeffMPSGEHereLast)

! Go throught the input string, pulling off words. Convert each as appropriate
	StartPos = 1
	Finished = .false.
	StartingSum = .false.
	BracketAfterSum = .false.
	InsideCoeffArguments = .false.
	JustFoundCoeff = .false.
	LastWord = ''
	
	do while(StartPos.le.llen.and. (.not.Finished))
! OrigState is state before process this word
	  OrigState = State
	  call GetNextWord(GAMSStyleExpression, StartPos, &
	    found, TrueStart, TrueEnd)
	  if(.not.found) then
	    Finished = .true .
	  else
! Have found another word. Process it.
	    ThisWord = GAMSStyleExpression(TrueStart:TrueEnd)
!	    write(*,*)'ThisWord=',trim(ThisWord)
	    WordLength = TrueEnd - TrueStart + 1
	    WordProcessed = .false.
	    NewWord = ThisWord(1:WordLength)  ! may be changed

	    if(.not.WordProcessed) then
! Process $sameas (but $ has been stripped off already)
	      if(EqualStringsIgnoreCase('sameas',ThisWord)) then
		State = 31 
		WordProcessed = .true.
		NewWord = ''
	      end if ! if(EqualStringsIgnoreCase('sameas',ThisWord)) then

	      if(OrigState.ge.31.and.OrigState.le.35) then
		NewWord = ''
		if(OrigState.eq.31) then
		  if(ThisWord.eq.'(') then
		    NewWord = '('
		    State=32
		  else
		  end if
		else if(OrigState.eq.32) then
		  if(.not.UseIndexStack) then
	            call GPSetName2Index(ThisWord, ThisIndex)
		  else if(UseIndexStack) then
		    call IndexToGPUseIndexStack( ThisWord, &
	  		DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
	  		ThisIndex)
		  end if
		  NewWord = trim(ThisIndex)//' EQ'
		  State = 33
		else if(OrigState.eq.33) then
		  if(ThisWord.eq.',') then
		    State=34
		  else
		  end if
		else if(OrigState.eq.34) then
		  if(.not.UseIndexStack) then
	            call GPSetName2Index(ThisWord, ThisIndex)
		  else if(UseIndexStack) then
		    call IndexToGPUseIndexStack( ThisWord, &
	  		DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
	  		ThisIndex)
		  end if
		  NewWord = ' '//trim(ThisIndex)  ! Space after "EQ"
		  State = 35
		else if(OrigState.eq.35) then
		  if(ThisWord.eq.')') then
		    NewWord = ')'
		    State=21   ! Expect logical  operator, so not 22
		  else
		  end if
		end if
		WordProcessed = .true.
	      end if ! if(OrigState.ge.31.and.OrigState.le.35) then

	    end if ! if(.not.WordProcessed) then

	    if(JustFoundCoeff) then
	      if(.not.ThisWord.eq.'(') then
! This coefficient has no arguments. Set JustFoundCoeff false.
	        JustFoundCoeff = .false.
! Now expect operator
		State = 22
	      end if
	    end if

	    if(.not.WordProcessed) then
! [04/06/04] See if is "LOG". If so convert to GEMPACK LOGE.
	      if(EqualStringsIgnoreCase(ThisWord(1:WordLength),'log')) then
		  WordProcessed = .true.
		  NewWord = 'LOGE' ! convert to upper case
	      end if
	    end if ! if(.not.WordProcessed) then

	    if(.not.WordProcessed) then
	      if(.not.StartingSum) then
! See if this word is "sum"
	        if(EqualStringsIgnoreCase(ThisWord(1:WordLength),'sum')) then
		  StartingSum = .true.
!		  write(*,*)'StartingSum is true'
	          BracketAfterSum = .false.
		  WordProcessed = .true.
		  NewWord = 'SUM' ! convert to upper case
	        end if
	      end if
	    end if ! if(.not.WordProcessed) then

	    if(.not.WordProcessed) then
! See if this is a "(" after a sum
	      if(StartingSum) then
		if(ThisWord.eq.'(') then
		  StartingSum = .false.
		  BracketAfterSum = .true.
!		  write(*,*)'BracketAfterSum is true'
		  WordProcessed = .true.
		end if
	      end if
	    end if

	    if(.not.WordProcessed) then
! See if this is a set after a sum
	      if(BracketAfterSum) then
		if(.not.UseIndexStack) then
	          call GPSetName2Index(ThisWord, ThisIndex)
		else if(UseIndexStack) then
		    call IndexToGPUseIndexStack( ThisWord, &
	  		DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
	  		ThisIndex)
		end if
		BracketAfterSum = .false.
		WordProcessed = .true.
		NewWord = trim(ThisIndex)//','//trim(ThisWord)
!		write(*,*)'Index added. NewWord is:', trim(NewWord)

! Look ahead to see if is a conditional sum
	        call GetNextWord(GAMSStyleExpression, TrueEnd+1, &
	          found, TrueStart2, TrueEnd2)
	        ThisWord2 = GAMSStyleExpression(TrueStart2:TrueEnd2)
		if(ThisWord2.eq.'$') then
! This begins condition after a sum. Convert "$" to ":"
		  NewWord = trim(NewWord)//' :'
! Do not process this word again
		  TrueEnd = TrueEnd2
		end if ! if(ThisWord2.eq.'$') then
	      end if
	    end if

	    if(.not.WordProcessed) then
! See if this is a bracket which marks beginnings of Coeff arguemnts
	      if(JustFoundCoeff) then
	        if(ThisWord.eq.'(') then
		  JustFoundCoeff = .false.
		  InsideCoeffArguments = .true.
!		  write(*,*)'InsideCoeffArguments is true'
		  WordProcessed = .true.
	        end if

	      else if(InsideCoeffArguments) then
! Process this argument
	        if(ThisWord.eq.')') then
		  InsideCoeffArguments = .false.
		  CurrentCoeffName = ''
!		  write(*,*)'Found end of coeff arguments'
		  WordProcessed = .true.
! Now expect value
		  State = 22
		else
! This must be an argument or a ","
		  if(ThisWord.eq.',') then
		    WordProcessed = .true.
		  else
! An argument. Current set in this position may be null
!  Update this in view of the current set in this position.
		    call findid(ThisWord, ThisSetSymbol)
		    if(.not.associated(ThisSetSymbol)) then
		      write(*,*)'ThisWord is:', trim(ThisWord)
		      call InternalErrorStop( &
			'ExpressionToGPSyntax3. ThisSetSymbol is null. Is this in fact a new set?')
		    end if
!		    write(*,*)'ExpressionToGPSyntax3. Calling UpdateOneArg. NextArgumentNumber is', NextArgumentNumber, &
!		      ' CurrentCoeffName is:', trim(CurrentCoeffName)
!		    call WriteArguments(GPCoeffMPSGECurrentCoeff%MaxArg, OutputText, LenOutput)
!		    write(*,*)'ExpressionToGPSyntax3. Arguments are:', trim(OutputText(1:LenOutput))
		    call UpdateOneArg(GPCoeffMPSGECurrentCoeff%MaxArg, &
			NextArgumentNumber, ThisSetSymbol%name)  
!		    call WriteArguments(GPCoeffMPSGECurrentCoeff%MaxArg, OutputText, LenOutput)
!		    write(*,*)'ExpressionToGPSyntax3. After UpdateOneArg, arguments are:', trim(OutputText(1:LenOutput))
		    NextArgumentNumber = NextArgumentNumber + 1
! Process the argument
		    if(INDEX(ThisWord,'"').gt.0) then
!  No change for a set element argument
		      WordProcessed = .true.
		    else
! This must be an argument which needs translating to a GEMPACK index
		      if(.not.UseIndexStack) then
	                call GPSetName2Index(ThisWord, ThisIndex)
		      else if(UseIndexStack) then
		        call IndexToGPUseIndexStack( ThisWord, &
	  		  DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
	  		  ThisIndex)
		      end if
		      WordProcessed = .true.
		      NewWord = trim(ThisIndex)
!		      write(*,*)'Argument translated to index:', trim(NewWord)
		    end if
		  end if ! if(ThisWord.eq.',') then..else..
	        end if ! if(ThisWord.eq.')') then..else..
	      end if ! else if(InsideCoeffArguments) then
	    end if ! if(.not.WordProcessed) then

	    if(.not.WordProcessed) then
! Recognise some reserved words which are not coefficients
	      ans1 = EqualStringsIgnoreCase(ThisWord,'not')
	      ans2 = EqualStringsIgnoreCase(ThisWord,'and')
	      ans3 = EqualStringsIgnoreCase(ThisWord,'or')
	      if(ans1.or.ans2.or.ans2) then
		WordProcessed = .true.
		NewWord = ThisWord
	      end if
	    end if ! if(.not.WordProcessed) then

!------------------------------------------------------------------------------------
	    if(.not.WordProcessed) then
! If find "=" check to see if it starts GAMS "=e=" and then convert to GEMPACK "="
	      if(ThisWord.eq.'=') then
! We will process this word here
		WordProcessed = .true.
		NewWord = '='
! [04/06/04] Look ahead.
	        call GetNextWord(GAMSStyleExpression, TrueEnd+1, &
	                found2, TrueStart2, TrueEnd2)
		if(found2) then
	          ThisWord2 = GAMSStyleExpression(TrueStart2:TrueEnd2)
!		  write(*,*)'Testing "=e=" part 1. ThisWord2 is:', trim(ThisWord2)
		  if(EqualStringsIgnoreCase(ThisWord2,'e')) then
! look ahead again
	            call GetNextWord(GAMSStyleExpression, TrueEnd2+1, &
	                found2, TrueStart2, TrueEnd2)
		    if(found2) then
	              ThisWord2 = GAMSStyleExpression(TrueStart2:TrueEnd2)
!		      write(*,*)'Testing "=e=" part 2. ThisWord2 is:', trim(ThisWord2)
		      if(ThisWord2.eq.'=') then
! Convert "=e=" to "="
		        NewWord = '='
		        write(*,*)'[Converted "=e=" to "="]'
! Do not process these words again
		        TrueEnd = TrueEnd2
		      end if ! if(ThisWord2.eq.'=') then
		    end if ! if(found2) then
		  end if ! if(EqualStringsIgnoreCase(ThisWord2,'e')) then
		end if ! if(found2) then
	      end if ! if(ThisWord.eq.'=') then
	    end if ! if(.not.WordProcessed) then
!------------------------------------------------------------------------------------

	    if(.not.WordProcessed) then
! Is this an operator
		if(ThisWord.eq.'+'.or.ThisWord.eq.'-'.or. &
			ThisWord.eq.'*'.or.ThisWord.eq.'/') then

		  if(ThisWord.eq.'*') then
! [04/06/04] Look ahead to see if is another * following. Convert GAMS ** to GEMPACK ^
	              call GetNextWord(GAMSStyleExpression, TrueEnd+1, &
	                found2, TrueStart2, TrueEnd2)
		      if(found2) then
	                ThisWord2 = GAMSStyleExpression(TrueStart2:TrueEnd2)
!		        write(*,*)'Testing "**". ThisWord2 is:', trim(ThisWord2)
		        if(ThisWord2.eq.'*') then
! Convert "**" to "^"
		          NewWord = '^'
		          write(*,*)'[Converted "**" to "^"]'
! Do not process this word again
		          TrueEnd = TrueEnd2
		        end if ! if(ThisWord2.eq.'*') then
		      end if ! if(found2) then
		  end if ! if(ThisWord.eq.'*') then

! [05/06/04] Separate this OrigState stuff from the above, otherwise do not
!  recognise "**"
		  if(OrigState.eq.22) then
		    State=21
		  end if

		end if ! if(ThisWord.eq.'+'.or.ThisWord.eq.'-'.or. (etc)

! All other words passed on unchanged
		WordProcessed = .true.

! Is this a coefficient? If so, add it to GPCoeffMPSGEHere
		if(IsLetter(ThisWord(1:1))) then
		  CurrentCoeffName = ThisWord
		  JustFoundCoeff = .true.

!
		  if(ConvertCommodityEtcNamesToLevels) then
	            if(IsSectorCommodityConsumer(CurrentCoeffName, TypeFound)) then
! If a sector, commodity or consumer, convert to its levels name
		      NewWord = GPLevelsName(CurrentCoeffName)
	            end if ! if(IsSectorCommodityConsumer(CurrentCoeffName, TypeFound) then
		  end if ! if(ConvertCommodityEtcNamesToLevels) then

! Just add this to GPCoeffMPSGEHere (not to GPCoeffMPSGEList)
!  Make it a new one - do not want to use any version in GPCoeffMPSGEList
!  since %next may not agree in GPCoeffMPSGEHere and GPCoeffMPSGEList
		  call GetNewGPCoeffMPSGE(NewGPCoeffMPSGE)
		  NewGPCoeffMPSGE%Name = CurrentCoeffName
		  nullify(NewGPCoeffMPSGE%MaxArg)
		  NextArgumentNumber = 1
		  nullify(NewGPCoeffMPSGE%next)
		  if(.not.associated(GPCoeffMPSGEHere)) then
!		    write(*,*) 'ExpressionToGPSyntax3. First in GPCoeffMPSGEHere'
	  	    GPCoeffMPSGEHere => NewGPCoeffMPSGE
	  	    GPCoeffMPSGEHereLast => NewGPCoeffMPSGE
		  else
!		    write(*,*) 'ExpressionToGPSyntax3. Another in GPCoeffMPSGEHere'
	  	    GPCoeffMPSGEHereLast%next => NewGPCoeffMPSGE
	  	    GPCoeffMPSGEHereLast => NewGPCoeffMPSGE
		  end if
		  nullify(GPCoeffMPSGEHereLast%next)
! Use GPCoeffMPSGECurrentCoeff as the name for this new one
		  GPCoeffMPSGECurrentCoeff => GPCoeffMPSGEHereLast ! or NewGPCoeffMPSGE
		end if ! if(IsLetter(ThisWord(1:1))) then
	    end if ! if(.not.WordProcessed) then

! Add NewWord to OutputString
! First check that OutputString has not become too long
	    if(LEN_TRIM(OutputString)+LEN_TRIM(NewWord).gt.LEN(OutputString)) then
	      call InternalErrorStop('Routine ExpressionToGPSyntax3. OutputString has become too long.')
	    end if
	    OutputString = trim(OutputString)//NewWord

! Prepare for next word
	    StartPos = TrueEnd + 1
	    LastWord = ThisWord

	  end if ! if(.not.found) then..else..

	end do ! do while(StartPos.le.llen.and. (.not.Finished))

! Are done
! First check if need to add "NE 0" to complete expression
	if(CompleteLogicalExpression) then
	  if(State.eq.22) then
	    OutputString = trim(OutputString)//' '//trim(CompletionStringForLogicalExpression)
	  end if
	end if

! Are done
        ExpressionToGPSyntax3 = OutputString
!        write(*,*)'ExpressionToGPSyntax3. Output is:', trim(OutputString)

!	write(*,*)'End of ExpressiontoGPSyntax3. WriteGPCoeffMPSGEList output follows.'
!	call WriteGPCoeffMPSGEList
!	write(*,*)'End of ExpressiontoGPSyntax3. End of WriteGPCoeffMPSGEList output.'
 

	return
	end function ExpressionToGPSyntax3

	subroutine IndexToGPUseIndexStack( &
! Input
	  ThisIndex, DimIndexStack, TopIndexStack, IndexStackSets, IndexStackIndexes, &
! Output
	  OutputIndex)
! Input
	character (len=*), intent(in) :: ThisIndex
	type (domain), pointer :: TheseArgs
	integer, intent(in) :: DimIndexStack, TopIndexStack
	character (len=*), intent(in) :: IndexStackSets(DimIndexStack)
	character(len=*), intent(in) :: IndexStackIndexes(DimIndexStack)
! Output
	character (len=*), intent(out) :: OutputIndex
! Local
	logical :: IndexInIndexStack
	integer :: i

	OutputIndex = ''

! Need to see if this index is on the index stack. If so, use the index there.
	  IndexInIndexStack = .false.
! [08/04/04] Go in REVERSE order, starting at the top of the index stack
	  do i=TopIndexStack,1,-1

	    if(.not.IndexInIndexStack) then
	      if(EqualStringsIgnoreCase(ThisIndex, IndexStackSets(i))) then
	        IndexInIndexStack = .true.
	        OutputIndex = IndexStackIndexes(i)
	      end if
	    end if
	  end do

	  if(.not.IndexInIndexStack) then
! [08/04/04] This is an error, I think
	    call InternalErrorStop('IndexToGPUseIndexStack. '//trim(ThisIndex)//' is not in index stack.')
	  end if

	return
	end subroutine IndexToGPUseIndexStack

!-------------------------------------------------------------------------------------------
! [03/06/04] Check that an auxiliary variable appears after $constraint: somewhere in the file
!  Ideally I think that this checking should be in MPSGE.F90
	subroutine CheckAuxiliaryIsInConstraint( &
! Input
	  ThisAuxiliaryVariableName, &
! Output
	  FoundInConstraint)
! Input
	character (len=*), intent(in) :: ThisAuxiliaryVariableName
! Output
	logical, intent(out) :: FoundInConstraint

! Local
	type(function), pointer :: CurrentFunction
	type(record), pointer :: CurrentRecord
	type(field), pointer :: CurrentField, FirstField
	character (len=128) :: ConstraintVariableName

	FoundInConstraint = .false.

	CurrentFunction => functionlist
	do while(associated(CurrentFunction))
	  CurrentRecord => CurrentFunction%firstrecord
	  FirstField => CurrentRecord%firstfield
	  if(EqualStringsIgnoreCase(FirstField%label,'$constraint')) then
	    ConstraintVariableName = FirstField%identtext
	    if(EqualStringsIgnoreCase(ThisAuxiliaryVariableName, ConstraintVariableName)) then
	      FoundInConstraint = .true.
	    end if
	  end if

	  CurrentFunction => CurrentFunction%next
	end do  ! while(associated(CurrentFunction))

	if(.not.FoundInConstraint) then
	  call ErrorStop('Did not find auxiliary variable '//trim(ThisAuxiliaryVariableName)//&
	    ' after $constraint: anywhere in the file.')
	end if

	end subroutine CheckAuxiliaryIsInConstraint
!-------------------------------------------------------------------------------------------

	logical function IsSectorCommodityConsumer(ThisName, TypeFound)
! Input
	character (len=*), intent(in) :: ThisName
! Output
	character (len=*), intent(out) :: TypeFound
! Local
	type(symbol), pointer :: ThisSymbol
	logical :: Found

	TypeFound = ' '
	Found = .false.
	ThisSymbol => idlist    ! idlist contains all symbols
	do while(.not.Found .and. associated(ThisSymbol))
	  if(ThisSymbol%type.eq.'sector'.or.ThisSymbol%type.eq.'commodity'.or.ThisSymbol%type.eq.'consumer') then
	    if(EqualStringsIgnoreCase(ThisName,ThisSymbol%name)) then
	      Found = .true.
	      TypeFound = ThisSymbol%type
	    end if
	  end if ! if(ThisSymbol%type.eq.'sector'.or.ThisSymbol%type.eq.'commodity'.or.ThisSymbol%type.eq.'consumer') then
	  ThisSymbol => ThisSymbol%next
	end do ! do while(.not.Found .and. associated(ThisSymbol))

	IsSectorCommodityConsumer = Found
	return	
	end function IsSectorCommodityConsumer

! [05/06/04] Function which converts $sector, $commodity or $consumer name to the name of the associated
!  GEMPACK levels variable
	character (len=llcs) function GPLevelsName(ThisSectorCommodityConsumerName)
! Input
! Fatal error if ThisSectorCommodityConsumerName is not a $sector, $commodity or $consumer
	character (len=*), intent(in) :: ThisSectorCommodityConsumerName

! Local
	type(symbol), pointer :: ThisSymbol
	character (len=128) :: TempName
	character (len=20) :: TypeFound
 
	if(IsSectorCommodityConsumer(ThisSectorCommodityConsumerName, TypeFound)) then
	  TempName = ThisSectorCommodityConsumerName
! Convert name to upper case
	  call upper(TempName)
	  if(TypeFound.eq.'sector'.or.TypeFound.eq.'commodity') then
	      GPLevelsName = trim(TempName)//'_L'
	  else if(TypeFound.eq.'consumer') then
	      GPLevelsName = 'VI_'//trim(TempName)
	  else
	    call InternalErrorStop('GPLevelsName. Expect one of these three.')
	  end if
	else
	    call InternalErrorStop('GPLevelsName. '//trim(ThisSectorCommodityConsumerName)//&
		' is not the name of a $sector, $commodity or $consumer.')
	end if
	
	return
	end function GPLevelsName
	
	
end module mpsgp